<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
    <channel>
        <title>Web Development - Blogs at Near Infinity</title>


        <link>http://www.nearinfinity.com/blogs/</link>
        <description>Employee Blogs</description>
        <language>en</language>
        <copyright>Copyright 2011</copyright>
        <lastBuildDate>Tue, 28 Jun 2011 13:04:53 -0500</lastBuildDate>
        <generator>http://www.sixapart.com/movabletype/</generator>
        <docs>http://www.rssboard.org/rss-specification</docs>
        
        <item>
            <title>Web Performance v. Usability</title>
            <description><![CDATA[<p>Looking through the web for standards on how to make your web pages more performant (i.e. using tools like <a href="http://developer.yahoo.com/yslow/">YSlow!</a>), one of the things that is mentioned is to put your css at the top and your javascript at the bottom.  The reason to do this is so that your content will render faster (and be styled) and not have to wait for the parsing of the javascript in order to display.</p>

<p>Recently I have been getting into using <a href="http://www.jqueryui.com">jQuery UI</a> a lot more.  I like the common look and feel, the ability to theme it easily, and am excited for all of the new enhancements and widgets that are coming.  The issue that I have found is that when jQuery UI initializes your widgets it adds the theming classes from the javascript.  This causes the page content to render (in a very ugly unstyled fashion) and then it "pops" into the nice styled page.  As a user also, I tend to hate this effect and find it very annoying.  So I set out to see what I could do to fix this and still keep the site performant.</p>

<h2>First attempt - pure <span class="caps">CSS</span></h2>

<p>At first I thought, well what if I just put the jQuery UI classes on the elements that I know will already receive those classes when jQuery UI ran?  This worked well for some of the page but there were still issues:</p>


<ol>
<li> Some of the jQuery UI widgets add in extra <span class="caps">DOM </span>elements to accomplish the look they are going for, so this still had the jumping effect</li>
<li> I was now bound to a specific version of jQuery UI because if they ever changed or tweaked their class names I would have to update all of my elements with the changes</li>
<li> By adding the classes on the server I increased the page size and content that needed to be downloaded to the browser</li>
</ol>




<h2>Second attempt - rearrange the JS</h2>

<p>Since the <span class="caps">CSS </span>way wasn't ideal and would cause a lot of maintenance I decided to see what would happen if I rearranged where I loaded the <span class="caps">JS. </span> I put all of the JS back in the head tag, so it would load (and parse) the JS before any content would display to the user.  This solution was better, however, there was still a little jumping of the page before it was fully styled.</p>

<h2>Third attempt - tweaking the JS calls</h2>

<p>Finally, I took a look at how I was calling the jQuery UI widget initializers.  I found that I was calling them inside of jQuery(window).load call.  I then did some research and realized that the difference between jQuery(window).load and jQuery(document).ready is actually pretty significant if you have a lot of images.  This is due to the fact that window load waits for the images to finish before being called where as document ready is called when the <span class="caps">DOM </span>is finished loading.  Changing those calls to be inside of a jQuery(document).ready block did the trick and the page loads without any jumping.</p>

<p>So from this exercise I found that as the web world moves towards more and more javascript based <span class="caps">UI'</span>s we will need to look more closely at these blanket performance statements and include usability in those measurements.</p>

<h2>Extra nugget:</h2>

<p>The pages in question above also load various content through ajax after the page loads.  I found a small performance gain when I kept the jQuery UI initializers in the document ready block and moved the ajax calls into the window load block.</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/chris_rohr/web_performance_v_usability.html</link>
            <guid>http://www.nearinfinity.com/blogs/chris_rohr/web_performance_v_usability.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">JavaScript</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">jquery</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">jquery-ui</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">performance</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">usability</category>
            
            <pubDate>Tue, 28 Jun 2011 13:04:53 -0500</pubDate>
        </item>
        
        <item>
            <title>CoffeeScript Slides</title>
            <description><![CDATA[ <p>Today is the <a href="http://www.nearinfinity.com">Near Infinity</a> Spring Conference. We have one conference in the fall and one in the spring for all our developers as well as invited guests. Today I gave a presentation on <a href="http://coffeescript.org">CoffeeScript</a> and shared the slides <a href="http://www.slideshare.net/scottleber/coffeescript-7642999">here</a>.</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/scott_leberknight/coffeescript_slides.html</link>
            <guid>http://www.nearinfinity.com/blogs/scott_leberknight/coffeescript_slides.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">JavaScript</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">coffeescript</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">javascript</category>
            
            <pubDate>Fri, 15 Apr 2011 15:19:06 -0500</pubDate>
        </item>
        
        <item>
            <title>HTML5 and CSS3 talk at RubyNation</title>
            <description><![CDATA[<div>Here is a link to my HTML5 and CSS talk that I gave today at RubyNation in Reston, VA.</div><div><br /></div><div>I knew I had to use a webpage to really showcase the new HTML and CSS features, so I built a JavaScript library to animate between section elements. I call it <a href="https://github.com/jharwig/sliderrr.js">sliderrr.js</a>.&nbsp;</div><div><br /></div><div><b>Keyboard commands:</b></div><div>left/right arrow - move previous/next slide</div><div>CMD-ESC - toggle presentation mode (ctrl-esc on windows)</div><div><br /></div><div><b>View Online:</b></div><div><a href="http://bit.ly/rubynation-html5">bit.ly/rubynation-html5</a>&nbsp;*</div><div><br /></div><div><b>Source on GitHub</b></div><div><a href="https://github.com/jharwig/HTML5Presentation">github.com/jharwig/HTML5Presentation</a></div><div><br /></div><div><br /></div><div>* Use Chrome/Safari for animation</div><div><br /></div><div><br /></div>]]></description>
            <link>http://www.nearinfinity.com/blogs/jason_harwig/html5_and_css3_talk_at_rubynat_1.html</link>
            <guid>http://www.nearinfinity.com/blogs/jason_harwig/html5_and_css3_talk_at_rubynat_1.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
            <pubDate>Sat, 02 Apr 2011 10:56:36 -0500</pubDate>
        </item>
        
        <item>
            <title>Exporting an ExtJs GridPanel to Word XML</title>
            <description><![CDATA[This blog post will lay out some of steps for exporting an ExtJs GridPanel to Word XML.&nbsp; This is useful if you want to save or print what's currently displayed in the grid.&nbsp; I am writing a subsequent post with steps on how to actually generate a Word XML file, but for now I'll focus on defining a grid, getting the grid's state, sending the grid's state to a controller, and prompting the user to save the generated Word XML document.<br /><br />Technologies used:<br />- Ruby on Rails<br />- mod_xsendfile for Apache2/Apache2.2<br />- ExtJs<br />- javascript<br /><br />At a high level, the following happens:<br />1. Gather and send the GridPanel state/configuration to the controller.<br />2. The controller runs a query and generates Word XML based on the query results.<br />3. The Word XML file is presented to the user via an "Open/Save As" dialog using XSendFile.<br /><br /><font style="font-size: 1.25em;"><b>Section 1: Getting the current state/configuration of the GridPanel</b></font><br /><br />If you're familiar with ExtJs GridPanel's you know they can be configured by each user viewing the panel.&nbsp; Columns can be added, removed, grouped, shortened, lengthened and repositioned.&nbsp; To capture the GridPanel's current state and pass it to the exporter, I wrote the following javascript.&nbsp; It calculates and returns an array containing the column order, which column data indexes belong to which titles, the grouped field (if any), the sorted field, the sorted direction, and the widths of each column.&nbsp; You will see where this function is used when I define the GridPanel in the next section.<br /><br /><br />
<pre class="prettyprint">var prepareExport = function(gridStore, gridColumnModel) {<br />&nbsp;&nbsp;&nbsp; var sort = null;<br />&nbsp;&nbsp;&nbsp; var direction = null;<br />&nbsp;&nbsp;&nbsp; if (gridStore.getSortState()) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; sort = gridStore.getSortState().field();<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; direction = gridStore.getSortState().direction;<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; var columnOrder = []; //ordered list of columns reflecting the GridPanel's state<br />&nbsp;&nbsp;&nbsp; var columnsToTitles = {}; //map of ext field mappings to column titles<br />&nbsp;&nbsp;&nbsp; var columnsToWidths = {}; //width of each column<br />&nbsp;&nbsp;&nbsp; var totalWidth = 0;<br />&nbsp;&nbsp;&nbsp; var groupByField = gridStore.groupField; //the store's current grouping field ('false' if not grouped)<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; var storeReaderMapping = gridStore.fields.items;<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; //check to see if the groupField has a corresponding mapping<br />&nbsp;&nbsp;&nbsp; for (var i = 0; i &lt; gridReaderMapping.length; i++) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (gridReaderMapping[i].name == gridStore.groupField &amp;&amp; gridReaderMapping[i].mapping != null) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; groupByField = gridReaderMapping[i].mapping;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; //get the total width of the displayed columns (this will be used later when generating the Word XML)<br />&nbsp;&nbsp;&nbsp; gridColumnModel.getColumnsBy(function(c) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!c.hidden) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; totalWidth = totalWidth + c.width;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; });<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; //iterate over the grid's column model.&nbsp; For displayed columns, get the ext field names (mappings) and column titles<br />&nbsp;&nbsp;&nbsp; gridColumnModel.getColumnsBy(function(c) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!c.hidden) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; for (var i = 0; i &lt; gridReaderMapping.length; i++) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (gridReaderMapping[i].name == c.dataIndex &amp;&amp; gridReaderMapping[i].mapping == null) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; columnOrder.push(gridReaderMapping[i].name);<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var key = gridReaderMapping[i].name;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; columnsToTitles[key] = c.header;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; columnsToWidths[key] = c.width/totalWidth;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else if (gridReaderMapping[i].name == c.dataIndex &amp;&amp; gridReaderMapping[i].mapping != null) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //if the name and mapping are different (i.e. a mapping exists), we need to push the mapping and not the name<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; columnOrder.push(gridReaderMapping[i].mapping);<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var key = gridReaderMapping[i].mapping;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; columnsToTitles[key] = c.header;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; columnsToWidths[key] = c.width/totalWidth;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; });<br />&nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; return [columnOrder, columnsToTitles, groupByField, sort, direction, columnsToWidths];<br />};</pre><br /><br /><br /><font style="font-size: 1.25em;"><b>Section 2: The GridPanel</b></font><br /><br />Here's a basic ExtJs GridPanel.&nbsp; Note the "exportButton" is defined in Section 3.<br /><br /><pre class="prettyprint">var gridReaderMapping = [<br />&nbsp;&nbsp;&nbsp; {name: 'id'},<br />&nbsp;&nbsp;&nbsp; {name: 'col_one'},<br />&nbsp;&nbsp;&nbsp; {name: 'col_two', mapping: 'some_mapping'},<br />&nbsp;&nbsp;&nbsp; {name: 'col_three'}<br />];<br /><br />var gridColumnModel = new Ext.grid.ColumnModel({<br />&nbsp;&nbsp;&nbsp; defaults: {sortable: true},<br />&nbsp;&nbsp;&nbsp; columns: [<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {header: 'ID', dataIndex: 'id'},<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {header: 'Column One', dataIndex: 'col_one'},<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {header: 'Column Two', dataIndex: 'col_two'},<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {header: 'Column Three', dataIndex: 'col_three'}<br />&nbsp;&nbsp;&nbsp; ]<br />});<br /><br />var store = new Ext.data.GroupingStore({<br />&nbsp;&nbsp;&nbsp; proxy: new Ext.dataHttpProxy({<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; url: 'give/me/my/data'<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; method: 'GET'<br />&nbsp;&nbsp;&nbsp; }),<br />&nbsp;&nbsp;&nbsp; reader: new Ext.data.JsonReader({<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; root: 'data',<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; totalProperty: 'total',<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; messageProperty: 'message'<br />&nbsp;&nbsp;&nbsp; }, gridReaderMapping)<br />});<br /><br />var grid = new Ext.grid.GridPanel({<br />&nbsp;&nbsp;&nbsp; id: 'gridpanel',<br />&nbsp;&nbsp;&nbsp; ds: gridStore,<br />&nbsp;&nbsp;&nbsp; cm: gridColumnModel,<br />&nbsp;&nbsp;&nbsp; sm: new Ext.grid.RowSelectionModel({<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; singleSelect: true<br />&nbsp;&nbsp;&nbsp; }),<br />&nbsp;&nbsp;&nbsp; tbar: [exportButton],<br />&nbsp;&nbsp;&nbsp; view: etc, etc, etc, etc...<br />});</pre><br /><br /><font style="font-size: 1.25em;"><b>Section 3: The Export Button</b></font><br /><br />When the export button is clicked it gathers all the necessary data from the GridPanel (columns, widths, etc) and passes that data along with query parameters to the controller.&nbsp; The controller runs a query and generates the Word XML file.&nbsp; Section 4 describes what happens when the Ajax request returns the data successfully.<br /><br />As I said at the beginning of this post, I will follow on with another post about the actual Word XML generation.&nbsp; The Word XML generation isn't too scary.&nbsp; If you're impatient, here are a few tips on Word XML generation.<br />&nbsp;&nbsp;&nbsp; 1. You can start by creating a small Word XML file with a single table using MS Word or Open Office.&nbsp; <br />&nbsp;&nbsp;&nbsp; 2. Open the XML file with the XML viewer/editor of your choice.&nbsp; Your table will be buried somewhere between &lt;w:body&gt; and &lt;/w:body&gt;.&nbsp; All the other sections of the XML can remain the same.&nbsp; <br />&nbsp;&nbsp;&nbsp; 3. You can create a series of templates for Word XML tables and rows based on the patterns you see in your Word XML sample.<br />&nbsp;&nbsp;&nbsp; 4. In your Word XML generator, substitute values into these templates to build tables.<br />&nbsp;&nbsp;&nbsp; 5. Insert the generated templates into a "master" template. <br /><br /><pre class="prettyprint">var exportButton = new Ext.Button({<br />&nbsp;&nbsp;&nbsp; renderTo: this.wrap,<br />&nbsp;&nbsp;&nbsp; listeners: {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; click: function (node, event) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; var exportConfig = prepareExport(grid.getStore(), grid.getColumnModel());<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Ext.Ajax.request({<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; url: 'url/to/query/for/data'<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; params: {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'columnsToTitles': Ext.util.JSON.encode(exportConfig[1]),<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'columnsToWidths': Ext.util.JSON.encode(exportConfig[5]),<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'columnOrder[]': exportConfig[0],<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'groupByExport': exportConfig[2],<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'groupBy': gridStore.groupField,<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'groupDir': 'ASC',<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'sort': exportConfig[3],<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'dir': exportConfig[4],<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'export': true<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; 'query': build_some_query_params_to_pass_to_the_controller<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; },<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; success: function(response, opts) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; window.location.href = 'path/to/exporter_controller/export_word_XML'<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; },<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; failure: function(response, opts) {<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; //output error message<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; },<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; scope: this<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }); <br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br />&nbsp;&nbsp;&nbsp; }<br />});</pre><br /><br /><font style="font-size: 1.25em;"><b>Section 4:&nbsp; Downloading the Word XML</b></font><br /><br />Using XSendFile to prompt the user with an "Open/Save As" dialog box.<br /><br /><pre class="prettyprint">class ExportController &lt; ApplicationController<br />&nbsp;&nbsp;&nbsp; def export_word_XML<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; filename = "#{X_SENDFILEPATH}/word_doc.xml"<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (File.exist?(filename))<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; send_file filename, :x_sendfile =&gt; true<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; else<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; render :nothing =&gt; true<br />&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; end<br />&nbsp;&nbsp;&nbsp; end<br />end</pre><br />Stay tuned for the upcoming Word XML <b><i>generation</i></b> blog post!<br />]]></description>
            <link>http://www.nearinfinity.com/blogs/michael_bevels/exporting_an_extjs_gridpanel_t.html</link>
            <guid>http://www.nearinfinity.com/blogs/michael_bevels/exporting_an_extjs_gridpanel_t.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">JavaScript</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Ruby</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
            <pubDate>Sun, 06 Mar 2011 16:43:27 -0500</pubDate>
        </item>
        
        <item>
            <title>JEE 6 and Spring MVC</title>
            <description><![CDATA[With the release of JEE 6 and the Servlet 3.0 specification came support for asynchronous servlets.  While continuations and Comet are not new, the fact that it is now part of the servlet specification, and could be "baked in" to an application, piqued my curiosity.  Although I have not used plain servlets in development for some time, I have been using Spring MVC.  So I wanted to see what would happen if I added asynchronous support to a Spring-MVC DispatcherServlet.  I created a very simple web application using Spring version 3.0.2 and annotation configuration.  I would like to make clear this is purely an experiment and is not being used production.
<h3>Environment Used</h3>
For this blog I'm using:
<ul>
<li>a T61 Thinkpad running Ubuntu 10.10(64Bit) and 4G ram</li>
<li>Java JDK 1.6.0_21</li>
<li>Glassfish Version 3. (I tried Tomcat 7 and Jetty 8, but had the best luck at this point with Glassfish)</li>
</ul>
<h3>DispatcherServlet Code</h3>
My first step was to extend Spring's DispatcherServlet.
<pre class="prettyprint">@WebServlet(urlPatterns = {"/async/*"}, asyncSupported = true, name = "async")
public class AsyncDispatcherServlet extends DispatcherServlet {
    private ExecutorService executor;
    private static final int NUM_ASYNC_TASKS = 15;
    private static final long TIME_OUT = 10 * 1000;
    private final Log log = LogFactory.getLog(AsyncDispatcherServlet.class);
@Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        executor = Executors.newFixedThreadPool(NUM_ASYNC_TASKS);
    }

    @Override
    public void destroy() {
        executor.shutdownNow();
        super.destroy();
    }

    @Override
    protected void doDispatch(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
        final AsyncContext ac = request.startAsync(request, response);
        ac.setTimeout(TIME_OUT);
        FutureTask task = new FutureTask(new Runnable() {

            @Override
            public void run() {
                try {
                    log.debug("Dispatching request " + request);
                    AsyncDispatcherServlet.super.doDispatch(request,response );
                    log.debug("doDispatch returned from processing request " + request);
                    ac.complete();
                } catch (Exception ex) {
                    log.error("Error in async request", ex);
                }
            }
        }, null);

        ac.addListener(new AsyncDispatcherServletListener(task));
        executor.execute(task);
    }</pre>
The only methods overridden were init, destroy and doDispatch. I won't go into detail on init and destroy, what they do is obvious.  All the interesting work is done in doDispatch.  The doDispatch method starts the asynchronous request, then wraps the call to super.doDispatch in a runnable and passes that into an executor service. There are a few key points to consider here:
<ol>
        <li>The @WebServlet annotation at the class definition level.  This is part of Servlet 3.0 specification, you can now declare servlets, filters etc via annotations, although you can still use web.xml.  To enable asynchronous support set the 'asyncSupported' attribute to true.</li>
	<li>On line 22 the setting of a timeout for the asyncContext object. In this case the timeout is 10 seconds</li>
	<li>On line 38 setting an AsyncContextEventListener.</li>
        <li>The application server thread returns almost immediately.</li>
</ol>
<h3>Listener Code</h3>
Getting the request to run asynchronously is only half the battle.  The other half is setting up hooks to handle different events during the life-cycle of the asynchronous request.  The Servlet 3.0 spec added the AsyncListener interface.  AsyncListener has 4 methods, onStartAsync, onComplete, onError and onTimeout. For the AsyncDispatcherServlet we have the inner class AsyncDispatcherServletListener  that takes a FutureTask object as a constructor argument.
<pre class="prettyprint">private class AsyncDispatcherServletListener implements AsyncListener {

        private FutureTask futureTask;

        public AsyncDispatcherServletListener(FutureTask futureTask) {
            this.futureTask = futureTask;
        }

        @Override
        public void onTimeout(AsyncEvent event) throws IOException {
            log.warn("Async request did not complete timeout occured");
            handleTimeoutOrError(event, "Request timed out");
        }

        @Override
        public void onComplete(AsyncEvent event) throws IOException {
            log.debug("Completed async request");
        }

        @Override
        public void onError(AsyncEvent event) throws IOException {
            log.error("Error in async request", event.getThrowable());
            handleTimeoutOrError(event, "Error processing " + event.getThrowable().getMessage());
        }

        @Override
        public void onStartAsync(AsyncEvent event) throws IOException {
            log.debug("Async Event started..");
        }

        private void handleTimeoutOrError(AsyncEvent event, String message) {
            PrintWriter writer = null;
            try {
                future.cancel(true);
                HttpServletResponse response = (HttpServletResponse) event.getAsyncContext().getResponse();
                //HttpServletRequest request = (HttpServletRequest) event.getAsyncContext().getRequest();
                //request.getRequestDispatcher("/app/error.htm").forward(request, response);
                writer = response.getWriter();
                writer.print(message);
                writer.flush();
            } catch (IOException ex) {
                log.error(ex);
            } finally {
                event.getAsyncContext().complete();
                if (writer != null) {
                    writer.close();
                }
            }
        }
    }</pre>
The onStartAsync and onComplete methods merely log a statement, but certainly could be used to open and close resources respectively.  The only methods that do any work are onTimeout and onError, delegating to the handleTimeoutOrError method, passing a message and the AsyncEvent object.  In handleTimeoutOrError we will call cancel on the futureTask object, write the message to the response stream, then mark the asyncContext as completed.  While we are writing the error directly to the response stream, we could have just as easily forwarded to an error page by using the commented out call to request.getRequestDispatcher().forward (obviously you would eliminate lines 38-40).
<h3>Web Application Structure</h3>
<p>
This web application is very simple and has only two controllers - SimpleViewControler and SearchController.
<pre class="prettyprint">

@Controller
public class SimpleViewController {
    
    @RequestMapping({"/","/index.htm"})
    public String showHome(){
        return "index";
    }

    @RequestMapping({"/error.htm"})
    public String error(){
        return "error";
    }
</pre>

<pre class="prettyprint">
@Controller
public class SearchController {

    @RequestMapping("/search.htm")
    public String doSearch(@RequestParam(value = "latency", defaultValue = "2000") long latency,
                                        @RequestParam(value = "blowup", defaultValue = "false") boolean blowUp,
                                        Model model) throws Exception {

        String searchResult = getSearchResult(latency, blowUp);

        model.addAttribute("result", searchResult);
        return "searchResult";
    }

    @RequestMapping("/search.ajax")
    public void doSearchAjax(@RequestParam(value = "latency", defaultValue = "2000") long latency,
            @RequestParam(value = "blowup", defaultValue = "false") boolean blowUp,
            HttpServletResponse response) throws Exception {

        String searchResult = getSearchResult(latency, blowUp);
        
        PrintWriter writer = null;
        try {
            writer = response.getWriter();
            writer.print(searchResult);
            writer.flush();
        } finally {
            if (writer != null) {
                writer.close();
            }
        }
    }

    private String getSearchResult(long latency, boolean blowUp) throws Exception {

        if (blowUp) {
            throw new RuntimeException("Bad error happened in controller");
        }

        Thread.sleep(latency);

        StringBuilder builder = new StringBuilder("Some search/whatever results being returned");
        Date now = new Date();
        builder.append(" @").append(now);
        
        return builder.toString();
    }
</pre>
The latency and blowup parameters in SearchController are used to simulate different response times and errors respectively.  Although there is the doSearchAjax method which writes directly to the response stream, in the tests that are run, we will only be using the doSearch method.  There are the usual context files, which are very light due to the annotation configuration and a web.xml file (needed for the regular DispatcherServlet). </p>
<p>

<h3>Testing</h3>
 Now it's time to see if this experiment works at all.   JMeter is a great tool and it is what I used to load test our simple web application.  I have set up three tests.
<ol>
<li>A "control" test - There are two thread-groups consisting of 50 threads each and will ramp up to run all threads in 3 seconds.  One thread group will make requests to /app/index.htm and the other thread group will make requests to /app/search.htm.  The thread-groups will execute simultaneously  and loop 3 times for a total of 300 requests.  Each thread-group has a "listener" attached to it to measure throughput, and there is a listener attached to the test to measure overall throughput. This test will give us our baseline.  The requests to /app/search.htm will not set any parameters, so each request will have the default value of 2 seconds for latency.
</li>
<li>The "asynchronous" test - This test will measure the effect of using asynchronous servlets in the application.  Setup is identical to the control test above with one exception - the search requests will go to /async/search.htm and hit the AsynchronousDispatcherServlet.
</li>
<li>An error condition test - This test will be structured a little differently.  The thread-group for /app/index.htm has a longer ramp up time, but will remain the same otherwise.  The thread group for /async/search.htm will add a JMeter option known as a 'RandomController'.  There will be 3 possible search requests sent, a valid request, a request with the latency parameter set to 12 seconds causing a timeout and a request with the blowup parameter set to true, so a RuntimeException will be thrown.
</li>
</ol>
<h3>Test Results</h3>
<table cellpadding="3" cellspacing="10" width="100%">
<tr>
<td>
<table cellpadding="3" cellspacing="10" width="100%">
<tr>
<th colspan="2" align="center">Control Test</th>
</tr>
<tr>
<th>Request</th>
<th>Throughput</th>
</tr>
<tr>
<td>Overall</td>
<td>296.174/minute</td>
</tr>
<tr>
<td>Index</td>
<td>164.489/minute</td>
</tr>
<tr>
<td>Search</td>
<td>148.569/minute</td>
</tr>
</table>
</td>
<td>
<table cellpadding="3" cellspacing="10" width="100%">
<tr>
<th align="center" colspan="2">Asynchronous Test</th>
<tr>
  <th>Request</th><th>Throughput</th>
<tr>
<tr>
   <td>Overall</td><td>849.177/minute</td>
</tr>
<tr>
   <td>Index</td><td>2,909.796/minute</td>
</tr>
<tr>
   <td>Search</td><td>429.84/minute</td>
</tr>
</table>
</td>
<td>
<table cellpadding="3" cellspacing="10" width="100%">
<tr>
<th colspan="2" align="center">Error Test</th>
<tr>
  <th>Request</th><th>Throughput</th>
<tr>
<tr>
   <td>Overall</td><td>115.848/minute</td>
</tr>
<tr>
   <td>Index</td><td>2,803.738/minute</td>
</tr>
<tr>
   <td>Search</td><td>57.974/minute</td>
</tr>
</table>
</td>
</tr>
</table>
<br/>
<p>
As we can see from the test results, sending the search requests through the AsyncronousRequestDispatcher increased application throughput.  The request per minute numbers don't mean that much though, given that the web application was so simple and the test was very contrived. What matters more is that the index requests had roughly the same response time and were seemingly unaffected when asynchronous support was used for the search requests</p>
<h3>Summary</h3>
<p>For me there were two main takeaways from this experiment:
<ul>
<li>Even though asynchronous support seemed help with throughput, it is still using a thread pool which consumes server resources, so it should be only be applied to very select parts of an application.</li>
<li>By setting timeouts and getting a chance to handle them gracefully via the event listener, asynchronous support acts a "circuit breaker" of sorts.  This could be valuable when your application makes requests to outside resources that may be down or otherwise unresponsive.</li>
</ul>
</p>
<h3>Resources</h3>
<p>Source for everything is <a href="http://github.com/bbejeck/spring_servlet3" target="new">available on github</a>.<br/> 
To run the JMeter tests<ol>
<li><a href="http://jakarta.apache.org/site/downloads/downloads_jmeter.cgi" target="new">Download JMeter</a> and extract the tar/zip file to some directory</li>
<li>Copy all of the *.jmx files in the jmeter directory from the github site for the code into &lt;JMeter install&gt;/bin. From the bin directory run jmeter or jmeter.bat depending on your platform.  Once JMeter is up and running select File and you should see AsyncWebTestControl.jmx, AsyncWebTestErrors.jmx, AsyncWebTest.jmx in the File menu.   Just click on one of those to open then Ctrl+r to run a test</li>
<li>Download the war file and deploy to glassfish.  I placed the war file in the autodeploy directory in glassfish.  On my laptop it's in /usr/local/servers/glassfishv3/glassfish/domains/domain1/autodeploy.</li>
</ol>
</p>]]></description>
            <link>http://www.nearinfinity.com/blogs/bill_bejeck/jee_6_and_spring_mvc.html</link>
            <guid>http://www.nearinfinity.com/blogs/bill_bejeck/jee_6_and_spring_mvc.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Java</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">Java Spring</category>
            
            <pubDate>Thu, 09 Dec 2010 00:12:30 -0500</pubDate>
        </item>
        
        <item>
            <title>Environment Specific Default Attachment Options for Paperclip</title>
            <description><![CDATA[<p><a href="https://github.com/thoughtbot/paperclip">Paperclip</a> is a popular Ruby file attachment solution for ActiveRecord. Following some basic setup, you can specify an attachment to an ActiveRecord model by calling the has_attached_file class method as shown in the example below.</p>

<pre class="prettyprint">
class Photo < ActiveRecord::Base
  has_attached_file :image,
    :styles => { :medium => '350x350>', :thumb => '100x100#' },
    :url    => ':class/:id/:style.:extension',
    :path   => ':rails_root/assets/:class/:id_partition/:style.:extension'
end
</pre>

<p>I love how easy it is to specify an attachment, but I don't like having to specify the :url and :path on all attachments for two reasons:</p>

<ol>
<li>It's not <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY</a>. With the <a href="https://github.com/thoughtbot/paperclip/wiki/Interpolations">Paperclip interpolations</a> I'm using, the :url and :path are never going to change within an environment no matter how many attachments I have across all my models.</li>
<li>Between environments I do need to change the path. In development I keep the attachments in :rails_root/assets but in production I want them somewhere else.</li>
</ol>

<p>Fortunately, changing the Paperclip attachment defaults per environment is really easy. In your environment config files, do something like the following.</p>

<pre class="prettyprint">
# development.rb (or use environment.rb to setup defaults for all)
Paperclip::Attachment.default_options[:url] = ':class/:id/:style.:extension'
Paperclip::Attachment.default_options[:path] = ':rails_root/assets/:class/:id_partition/:style.:extension'

# production.rb
Paperclip::Attachment.default_options[:url] = ':class/:id/:style.:extension'
Paperclip::Attachment.default_options[:path] = '/usr/local/assets/:class/:id_partition/:style.:extension'
</pre>

<p>Adding those defaults in your environment configuration files means you can keep your models DRY and free of any ugly code used to change options depending on the environment. Isn't this nicer?</p>

<pre class="prettyprint">
class Photo < ActiveRecord::Base
  has_attached_file :image, 
    :styles => { :medium => '350x350>', :thumb => '100x100#' }
end
</pre>
]]></description>
            <link>http://www.nearinfinity.com/blogs/jeff_kunkle/environment_specific_default_a.html</link>
            <guid>http://www.nearinfinity.com/blogs/jeff_kunkle/environment_specific_default_a.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Ruby</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
            <pubDate>Tue, 07 Dec 2010 09:09:34 -0500</pubDate>
        </item>
        
        <item>
            <title>Session Storage in JRuby on Rails</title>
            <description><![CDATA[There are many ways to store sessions in Ruby on Rails, but by using JRuby, we get another option that I think supersedes the common solutions... Using the Java Server's built in session store.<br /><br /><h2>First... The implementation</h2>
This is assuming that you are running JRuby and using a tool like warbler to deploy to a Java server like Tomcat.<br /><br />config/initializers/session_store.rb<br />
<pre class="prettyprint"># check if we're running in a java container
if defined?($servlet_context)
    require 'action_controller/session/java_servlet_store'
    # tell rails to use the java container's session store
    ActionController::Base.session_store = :java_servlet_store
else
    # other session store for development in webrick/mongrel<br />    # setup cookie based session<br />    ActionController::Base.session = {<br />        :key    =&gt; '_dd_session',<br />        :secret =&gt; '&lt;Your really long random secret key&gt;'<br />    }<br />end
</pre>This will store your rails session in Tomcat's session store exactly as if you were running a Java web framework.<br />
<br /><h2>Second... Why?</h2>There are a few common solutions starting with the rails default.<br /><br /><b>Cookie Store:</b> This is not very secure, limited in size, and sends a lot of data back and forth to the client. It is strongly recommended to not use this for production systems.<br /><b>File Store:</b> Stores sessions on the file system. Every cookie access involves file system IO. Does not support clustering by default but can be achieved through a SAN or shared storage.<br /><b>ActiveRecord:</b> Stores sessions in the database. Slow due to database IO. Natively supports clustering.<br /><b>Memcached:</b> Stores sessions in Memcached instance. Very popular and works well with clusters. Can run into RAM issues on systems with lots of users. Requires an instance of Memcached running.<br /><b>Java Servlet Store:</b> Works just like your other Java applications. Java Servers can be configured to cluster sessions. Uses the JSESSIONID cookie or url param (in Tomcat)<br /><br /><h2>Conclusion</h2>This won't be the solution for everyone, but if you're deploying a JRuby on Rails app into an infrastructure based on Java, then it provides a simple and efficient solution.<br />]]></description>
            <link>http://www.nearinfinity.com/blogs/andrew_avenoso/session_storage_in_jruby_on_ra.html</link>
            <guid>http://www.nearinfinity.com/blogs/andrew_avenoso/session_storage_in_jruby_on_ra.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">JRuby</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Java</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Ruby</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">jruby</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">ruby</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">session</category>
            
                <category domain="http://www.sixapart.com/ns/types#tag">tomcat</category>
            
            <pubDate>Mon, 09 Aug 2010 12:30:00 -0500</pubDate>
        </item>
        
        <item>
            <title>Selenium Mojo : Protoype Bindings in Selenium</title>
            <description><![CDATA[<font style="font-size: 1.25em;"><b>Introduction</b></font><br /><br />On my current project we have been involved in converting some of the hundreds of manual tests that are run by our Test Team every release into a suite of automated Selenium RC tests.<br /><br />During the course of this adventure my crew found several instances where XPath and native JavaScript were not sufficiently expressive to find elements in some of our more complicated interfaces. <br /><br />Since our web app uses the Prototype/Scriptaculous JavaScript framework we wanted to find a way to make the locating power of Prototype available within Selenium RC.<br /><br />We developed approaches for both Selenium 0.9.2 and Selenium 1.0.3 (which had better programmatic support for adding JavaScript user extensions to Selenium).<br /><br /><br /><font style="font-size: 1.25em;"><b>Selenium 0.9.2</b></font><br /><br />Selenium RC provides the capability to add "user extensions" to augment its JavaScript core. <br /><br />See <a href="http://seleniumhq.org/docs/08_user_extensions.html">http://seleniumhq.org/docs/08_user_extensions.html</a> for detailed information on how to set this up. <br /><br />We wrote the following user-extension.js file:<br /><br /><pre class="prettyprint">Selenium.prototype.setupProtoypeJS = function() {<br />&nbsp;&nbsp;&nbsp; id = selenium.browserbot.getCurrentWindow().$;<br />&nbsp;&nbsp;&nbsp; css = selenium.browserbot.getCurrentWindow().$$;<br />}</pre><br />In our code we have a base class for all our test cases. To this we added our own waitForPage() method:<br /><br /><pre class="prettyprint">public void waitForPage() {<br />&nbsp;&nbsp;&nbsp; selenium.waitForPage('60000')<br />&nbsp;&nbsp;&nbsp; proc.doCommand('setupPrototypeJS', [])<br />}</pre><br />Thus every time the page reloads (which clears the JavaScript context) we call waitForPage() and this command is re-executed. It creates two global variables (id and css) and binds them to Prototype's $ and $$ functions respectively.<br /><br /><i>Note: The reason we choose id and css instead of $ and $$ was that Groovy considers $ in Strings to be a special character and we would have had to escape it each time it was used</i>.<br /><br />The Prototype selectors can now be used in Selenium RC like this:<br /><br /><pre class="prettyprint">selenium.click("dom=id('foo')")<br />selenium.click("dom=css('.bar')")<br />selenium.click("dom=css('span.foo a.baz')")</pre><br /><i>Note: You still have to specify the dom locator type so Selenium RC will know to execute your locator string as JavaScript.&nbsp; <br /></i><br /><br /><font style="font-size: 1.25em;"><b>Selenium 1.0.3</b></font><br /><br />In more recent version of Selenium RC the project added the setExtensionJs() method. This allows you to set extension JavaScript programmatically prior to starting the selenium client:<br /><br /><pre class="prettyprint">selenium = new DefaultSelenium(...)<br />selenium.setExtensionJs('...')<br />selenium.start()</pre><br />This made it much easier to implement our Prototype bindings. The only trick was that the JavaScript seems to be executed prior to having access to a page context and is also only executed once. This required us to take a different approach.<br /><br />We created id and css as global functions instead of variables. This allowed us to defer accessing the current window until the functions were actually invoked. &nbsp; <br /><br /><pre class="prettyprint">selenium.setExtensionJs('''<br />        id = function(value) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;    return selenium.browserbot.getCurrentWindow().$(value);<br /><div id=":w0" class="ii gt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; css = function(value) {<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return selenium.browserbot.<wbr>getCurrentWindow().$$(value);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />''');</div></pre> <br /><i>Note: The above code snippet is written in Groovy which allows multiline Strings.<br /></i><br />The Prototype selectors are used in Selenium RC like before:<br /><br /><pre class="prettyprint">selenium.click("dom=id('foo')")<br />selenium.click("dom=css('.bar')")<br />selenium.click("dom=css('span.foo a.baz')")</pre><br /><br /><br />I would be interested in hearing feedback from anyone who has a chance to use this technique!<br />]]></description>
            <link>http://www.nearinfinity.com/blogs/stephen_mouring_jr/selenium_mojo_protoype_binding.html</link>
            <guid>http://www.nearinfinity.com/blogs/stephen_mouring_jr/selenium_mojo_protoype_binding.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Groovy</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">JavaScript</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Testing</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
            <pubDate>Sat, 24 Apr 2010 14:00:36 -0500</pubDate>
        </item>
        
        <item>
            <title>Sharepoint ASP .Net Ajax Configuration</title>
            <description><![CDATA[In the world of web development, there is a little thing called ajax. Ajax is so simple because it is built in to Javascript. I like to use ajax to make web applications that look like they are not stuck in the past. Tools like jQuery make ajax so simple with its commands like:<div><pre class="prettyprint">$.get $.post $.load</pre>ASP .Net has, what they tout as ultra simple, the update panel for ajax post backs to the server. But, this tool is not as simple as it seems. While deceptively simple to stick on a page and wire up to the code behind, it takes much more to make this tool work.<div><br /><div>Like everything else in the Microsoft world, to make ASP .Net have ajax requires a dll and, through reading the documentation, a crap load of changes to the web.config file. Sure, it is easy to get the web.config all nice and set up if you have Visual Studios do it for you. Just create a new Web Site and start debugging the website. Voila, all of the configuration setting needed to use ajax are there.<br /></div><div><br /></div><div>But, for those whose have to do through code for, say, a Sharepoint web site that has to be deployed anywhere, they feel the pain of drudging through the required assembly strings and making SPWebConfigModifications. So, the first step on the path to Sharepoint ajaxiness is to go out to all the dlls and collect all the assembly strings needed:</div><div><br /><pre class="prettyprint">const string scriptResourceHandler = "System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
const string scripthandlerfactory = "ScriptHandlerFactory";
const string scripthandlerfactoryappservice = "ScriptHandlerFactoryAppService";
const string scriptresource = "ScriptResource";
const string scriptModuleAssembly = "System.Web.Handlers.ScriptModule,System.Web.Extensions,Version=3.5.0.0,Culture=Neutral,PublicKeyToken=31bf3856ad364e35";
const string webScriptAssembly = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35";
const string webExtensionAssembly = "System.Web.Extensions,Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"</pre>After you have done that, or just copied the above assemblies, those assemblies have to be added to the web.config. That is where the SPWebConfigModification comes into play. First, you'll want to clear the modifications otherwise, modifications might appear for items that are long gone.&nbsp;</div><div><br /><pre class="prettyprint">webApp.WebConfigModifications.Clear();</pre>After that is set up, there is quite a bit to add to the WebConfigModification collection. Here OWNER, is something you set somewhere else and keep handy for when you have to remove all of the changes from the web.config.</div><div><br /><pre class="prettyprint">webApp.WebConfigModifications.Add(CreateControlSection());		webApp.WebConfigModifications.Add(CreateSafeControl(webExtensionAssembly,"System.Web.UI"));
webApp.WebConfigModifications.Add(CreateAjaxAssembly(webExtensionAssembly));			webApp.WebConfigModifications.Add(CreateHttpScriptHandler(scriptModuleAssembly,"ScriptModule"));
webApp.WebConfigModifications.Add(CreateScriptResource(scriptResourceHandler,"ScriptResource.axd","GET,HEAD"))
webApp.WebConfigModifications.Add(CreateScriptResource(webScriptAssembly,"*_AppService.axd","*"));
webApp.WebConfigModifications.Add(CreateScriptResource(webScriptAssembly,"*.asmx","*"));
webApp.WebConfigModifications.Add(CreateWebServerSection());
webApp.WebConfigModifications.Add(CreateWebServerHandlerSection());
webApp.WebConfigModifications.Add(RemoveWebServiceHandler(scripthandlerfactory));
webApp.WebConfigModifications.Add(RemoveWebServiceHandler(scripthandlerfactoryappservice));
webApp.WebConfigModifications.Add(RemoveWebServiceHandler(scriptresource));
webApp.WebConfigModifications.Add(CreateWebServiceHandler(webScriptAssembly,"*.asmx","*",scripthandlerfactory));
webApp.WebConfigModifications.Add(CreateWebServiceHandler(webScriptAssembly,"*_AppService.axd","*",scripthandlerfactoryappservice));webApp.WebConfigModifications.Add(CreateWebServiceHandler(scriptResourceHandler,"ScriptResource.axd", "GET,HEAD", scriptresource));
webApp.Farm.Services.GetValue<spwebservice>().ApplyWebConfigModifications();
webApp.Update();
/* Thus begins the many methods to add each little piece of the web.config */
private SPWebConfigModification CreateScriptResource(string assembly,string path,string verb) {
      return new SPWebConfigModification {
		Path = "configuration/system.web/httpHandlers",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture,"add[@verb='{2}'][@path='{1}'][@type='{0}'][@validate='false']",assembly,path,verb),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<add verb="{2}" path="{1}" type="{0}" validate="false">", assembly,path,verb)
	};
}

private SPWebConfigModification CreateWebServiceHandler(string assembly,string path,string verb,string name) {
	return new SPWebConfigModification {
		Path = "configuration/system.webServer/handlers",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture,"add[@verb='{2}'][@path='{1}'][@type='{0}'][@preCondition='integratedMode'][@name='{3}']",assembly,path,verb,name),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<add verb="{2}" path="{1}" type="{0}" precondition="integratedMode" name="{3}">", assembly,path,verb,name)
	};
}
private SPWebConfigModification RemoveWebServiceHandler(string name) {
	return new SPWebConfigModification {
		Path = "configuration/system.webServer/handlers",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture,"add[@name='{0}']",name),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<remove name="{0}">",name)
	};
}

private static SPWebConfigModification CreateHttpScriptHandler(string assembly,string name) {
	return new SPWebConfigModification {
		Path = "configuration/system.web/httpModules",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "add[@name='{0}'] [@type='{1}']",name, assembly),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format("<add name="{0}" type="{1}">",name, assembly)
	};
}

private static SPWebConfigModification CreateAssembly(string assembly) {
	return new SPWebConfigModification {
	        Path = "configuration/system.web/compilation/assemblies",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "add[@assembly='{0}']", assembly),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format(CultureInfo.InvariantCulture, "<add assembly="{0}">", assembly)
	};
}
private static SPWebConfigModification CreateAjaxAssembly(string assembly) {
	return new SPWebConfigModification {
		Path = "configuration/system.web/pages/controls",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "add[@tagPrefix='{0}'][@namespace='{1}'][@assembly='{2}']","asp","System.Web.UI", assembly),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format(CultureInfo.InvariantCulture, "<add tagprefix="{0}" namespace="{1}" assembly="{2}">","asp","System.Web.UI", assembly)
	};
}
private static SPWebConfigModification CreateSafeControl(string assembly, string nameSpace) {
	return new SPWebConfigModification {
		Path = "configuration/SharePoint/SafeControls",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
		Name = string.Format(CultureInfo.InvariantCulture, "SafeControl[@Assembly='{0}'][@Namespace='{1}'][@TypeName='*'][@Safe='True']", assembly, nameSpace),
		Owner = OWNER,
		Sequence = 0,
		Value = string.Format(CultureInfo.InvariantCulture, "<safecontrol assembly="{0}" namespace="{1}" typename="*" safe="True">", assembly,				nameSpace)
	};
}
private static SPWebConfigModification CreateControlSection() {
	return new SPWebConfigModification {
		Path = "configuration/system.web/pages",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
		Name = "controls",
		Value =@"<controls></controls>",
		Sequence = 0,
		Owner = OWNER
	};
}
private static SPWebConfigModification CreateWebServerSection() {
	return new SPWebConfigModification {
		Path = "configuration",
	        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
		Name = "system.webServer",
		Value =@"<system.webserver></system.webserver>",
		Sequence = 0,
		Owner = OWNER
	};
}
private static SPWebConfigModification CreateWebServerHandlerSection() {
       return new SPWebConfigModification {
		Path = "configuration/system.webServer",
		Type = SPWebConfigModification.SPWebConfigModificationType.EnsureSection,
		Name = "handlers",
		Value =@"<handlers></handlers>",
		Sequence = 0,
		Owner = OWNER
	};		
}</safecontrol></add></add></add></remove></add></add></spwebservice></pre><br />So, why on earth does it take that much code to generate the xml required to use ajax in Sharepoint?</div></div></div>]]></description>
            <link>http://www.nearinfinity.com/blogs/sean_howell/sharepoint_asp_net_ajax_configuration.html</link>
            <guid>http://www.nearinfinity.com/blogs/sean_howell/sharepoint_asp_net_ajax_configuration.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">.NET</category>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
            <pubDate>Tue, 02 Feb 2010 18:34:17 -0500</pubDate>
        </item>
        
        <item>
            <title>Several Must Have Firebug-Related Firefox Extensions</title>
            <description><![CDATA[ <p>Last week while doing the usual (web development stuff) I discovered a few Firefox extensions I didn't even know I was missing until I found them by accident. The "accident" happened while adding Firebug to a Firefox that was running in a VMWare Fusion Windows virtual machine on which I was testing in, gasp, Windows. I went to find add-ons and searched for Firebug. And up came not only <a href="http://getfirebug.com/">Firebug</a> but also results for <a href="http://www.softwareishard.com/blog/firecookie/">Firecookie</a>, <a href="http://robertnyman.com/firefinder/">Firefinder</a>, <a href="http://robertnyman.com/inline-code-finder/">Inline Code Finder for Firebug</a>, and <a href="http://tools.sitepoint.com/codeburner/firefox">CodeBurner for Firebug</a>.</p>

<p>Of course everyone doing web development uses Firebug (or really should anyway) since it rules. But these other extensions provide some <i>really</i> nice functionality and complement Firebug perfectly. Here's a quick run down:</p>

<h3>Firecookie</h3>

<p>Firecookie lets you see all the cookies for a site, add new ones, remove existing cookies, etc. It gives useful information about each cookie like the name, value, raw value (if URI-encoded), domain, size, path, expiration, and security. Very cool.</p>

<style type="text/css">
img.border {
   margin-bottom: 10px;
   border: 1px solid #021a40;
}
</style>

<img class="border" src="http://www.sleberknight.com/blog/sleberkn/resource/firecookie.png" alt="Firecookie Firefox Add-On" title="Firecookie Firefox Add-On"/>

<h3>Firefinder</h3> 

<p>Firefinder for Firebug lets you search for elements on a page using either CSS expressions or an XPath query. In the list of matching elements, you can expand each result, inspect the element by clicking the "Inspect" link, or click "FriendlyFire" which will copy the content you're looking at and post it up to <a href="http://jsbin.com/">JS Bin</a>. (Be careful with this one if you have code you'd rather not have going up over the wire to a different web site.) Firefinder also puts a dashed border around each matching element it found. As you hover over search results, it highlights the matching element in the page. This is really useful when you want to find all elements matching a CSS expression or when you'd like to use XPath to find specific elements. Nice.</p>

<img class="border" src="http://www.sleberknight.com/blog/sleberkn/resource/firefinder.png" alt="Firefinder Firefox Add-On" title="Firefinder Firefox Add-On"/>

<h3>Inline Code Finder for Firebug</h3>

<p>The Inline Code Finder does just that. It finds inline CSS styles, JavaScript links, and inline events, and reports the number of each of these in its results pane. Even better, it highlights each of these problems on the page  you are viewing with a thick red border, and as you hover over them it shows you what the problem is in a nicely tooltip. This is really nice to help you become less obtrusive by writing more unobtrusive JavaScript and avoiding inline styles. For older sites or sites that weren't designed with "unobtrusivity" in mind though, be warned that there might be a lot of red on the page!</p>

<img class="border" src="http://www.sleberknight.com/blog/sleberkn/resource/inlinecodefinder.png" alt="Inline Code Finder Firefox Add-On" title="Inline Code Finder Firefox Add-On"/>

<h3>CodeBurner for Firebug</h3>

<p>CodeBurner for Firebug provides an inline HTML and CSS reference within Firebug. It allows you to search for HTML elements or CSS styles and shows a definition and an example. It also provides links to the awesome <a href="http://www.sitepoint.com/">Sitepoint</a> reference and even to the Sitepoint live demos of the feature you are learning about. This is so unbelievably useful to have a HTML and CSS references directly within Firebug it isn't even funny. Thanks Sitepoint.</p>

<img class="border" src="http://www.sleberknight.com/blog/sleberkn/resource/codeburner.png" alt="CodeBurner Firefox Add-On" title="CodeBurner Firefox Add-On"/>]]></description>
            <link>http://www.nearinfinity.com/blogs/scott_leberknight/several_must_have_firebug-rela.html</link>
            <guid>http://www.nearinfinity.com/blogs/scott_leberknight/several_must_have_firebug-rela.html</guid>
            
                <category domain="http://www.sixapart.com/ns/types#category">Web Development</category>
            
            
                <category domain="http://www.sixapart.com/ns/types#tag">firefox firebug</category>
            
            <pubDate>Mon, 28 Sep 2009 12:47:51 -0500</pubDate>
        </item>
        
    </channel>
</rss>

