tag:blogger.com,1999:blog-25133381981287328932024-03-05T10:51:44.666+00:00Blogging Dot Net (and jQuery too!)Solutions to interesting problems.James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.comBlogger29125tag:blogger.com,1999:blog-2513338198128732893.post-46231897075413085642010-07-13T18:53:00.001+01:002010-07-13T18:53:43.513+01:00Simple OOXML For OOXML SDK v 2.0 released<p><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0])_"></a></p> <p>The goal of the Simple OOXML project has always been to create documents and spreadsheets using minimum resources, including a server environment. The library provides commonly used functionality whilst hides away the details of creating open xml documents and without a large performance overhead. Documents created with this library and the Open Office SDK can be viewed using Microsoft Excel/Microsoft Word or OpenOffice as well as any third party that supports the format. </p> <p> </p> <h3>Getting Started</h3> <p>Simple OOXML adds the <em>DocumentFormat.OpenXml.Extensions</em> namespace to version 2.0 of the Open Office SDK. It allows developers to create spreadsheets and documents either from scratch or using predefined templates. All functionality is represented by static functions for high performance tasks, or higher level wrapper functions can provide simpler code expressions with some minor performance loss.  </p> <p>The following classes are provided:</p> <ul> <li><em>SpreadsheetReader</em> - manipulation of templates, retrieval of document parts, row and column reference functionality </li> <li><em>SpreadsheetWriter</em> - writing of document parts and creation of document level attributes. Add or remove spreadsheets. </li> <li>SpreadsheetStyle - encapsulates font, border and fill handing in a spreadsheet. </li> <li><em>WorsheetReader</em> - retrieves cell and style information from a worksheet </li> <li><em>WorksheetWriter</em> - allows the pasting or insertion of data and style - using simple value types or <em>DataTables</em> - at a cell or range reference. </li> <li><em>DocumentReader</em> - retrieval of document templates. </li> <li><em>DocumentWriter</em> - pastes and saves text and text lists using predefined bookmarks. </li> </ul> <p>Download the source files to view the source code, examples as well as a unit testing library which is a useful reference to all the features of the library. Users of the unsupported <em>ExcelPackage</em> library could consider using this library instead. </p> <p>Simple OOXML is licensed under the LGPL. Requires .Net Framework 3.5 or later and can be downloaded from <a href="http://simpleooxml.codeplex.com" target="_blank">CodePlex</a>.</p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-6302203822049232612010-05-19T09:46:00.003+01:002010-05-19T09:49:48.159+01:00VS2010 The mappings for the solution could not be found<p>When trying to open a project with VS 2010 that used Visual SourceSafe, you may receive the following error:</p>
<p><span style="font-style:italic;">The mappings for the solution could not be found</span></p>
<p>To fix this problem, go to Tools -> Options -> Source Control -> Plug-in Selection and change to the Visual Sourcesafe plugin from the TFS plugin.</p>
<p>Another reason to switch to svn ...</p>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-84476856553669132502010-04-19T18:33:00.001+01:002010-04-19T18:39:39.142+01:00Coming to a browser near you – HTML 5<p>Found this great web based slide show detailing the changes and additions that make up HTML 5.0</p> <p><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDVrTPQTLoNCeJTqSRSL3qGrqy_mLI4dmqGBEIvQdY_zBoHV_WCbOSo9vyIPynCGM3XD4XZXMGQrsQKS3vNGRP4cZ1bxkc5Sn-RqUSS2buQQpuTuNBRLfz07A7AZh3IFlJuL1v1iWoXV58/s1600-h/progress%5B2%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="progress" border="0" alt="progress" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDfaP1QSC-PlUFU8S5ybEqK_HbvPcWsEhx7xMKx3lADFQmsxoXVYe-VyVM8w5c1ZGhSlC4_Oh7bNiZes1B1G0x9rCUXzgwVL6Y22t3uarrctYfTCPzUhyAZ5Ke6hqwFKqMMsgdQMfiDw2C/?imgmax=800" width="244" height="214" /></a> <a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie2Ofry0qDGRaZk1sOD6SE8yw61PPZgMO4Ayx_q7IpwuOiUYdIZM_c2MiSGGO6sPOVcvynnxNwfdOihhda3KbC-FzaLNzgOaXdbdQbIgjIlBNonoy4_KCV_PvW1jnzKgIZquKog4HReP9z/s1600-h/webworkers%5B5%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="webworkers" border="0" alt="webworkers" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghDUV5a0qkYqozEQt2ONBRiHWePVdy1TKbFlEhFD4l34Nz6NwyUlzjXEKJNp4WwYAD2lb3GcnIB5fRlJ9B_TDRU7wYmn94vPcCeMzwu2asnBWged4IdwgMWqTBVC9iBOmgzD8vB7DeXB98/?imgmax=800" width="244" height="214" /></a> </p> <p><a href="http://apirocks.com/html5/html5.html#slide1">http://apirocks.com/html5/html5.html#slide1</a></p> <p>(Warning – not IE friendly)</p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-78849509850552124782010-04-19T18:30:00.001+01:002010-04-19T18:30:39.127+01:00Great comparison of web browser performance<p> </p> <p>Jason Gube at sixrevisions.com has posted a great <a href="http://sixrevisions.com/infographics/performance-comparison-of-major-web-browsers/" target="_blank">article comparing browser performance</a>. It pretty much echos day to day performance I’m seeing and backs up my decision to switch to Chrome.</p> <img src="http://images.sixrevisions.com/2009/10/15-03_performance_comparison_of_web_browsers_large.jpg" /> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-38569444326711926792010-04-09T22:59:00.001+01:002010-04-09T22:59:24.062+01:00Hitting the thousand mark on stack overflow<p>The last few weeks have seen me actively participating in the community of programmer and pundits known as stackoverflow.com.</p> <p>I set myself a target of reaching 1000 rep in two weeks and Im really glad to say I managed to do it in 11 days, thanks in part to a particularly feisty conversation about team participation vs individualism and how it relates to building and testing software.</p> <p>My observations are that once a popular user (read user with high reputation or awards) replies to a question, most other users will jump on that band wagon. In practice, choosing other responses that are voted up even only once or twice may be more prudent. </p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-22202753486377847532010-02-24T21:43:00.001+00:002010-02-24T21:43:07.716+00:00Javascript Localization using .Net Resource files and jQueryAs a web developer I'm shifting more and more code to the client, and a few weeks ago an interesting situation came up on a multi-lingual project. ie wanted to include translations for validation messages in jQuery code, but stay with the great .Net resource file model. <div></div> <div>What I came up with was a pattern using JQuery AJAX and JSON to download the resource file to the browser. The translations are available using the same object notation available on the server eg <div> <pre style="width: 900px" class="code">// -- Localisation --
var localResources;
var globalResources;
//Sample JSON for javascript resource values eg {TrackDetail:{HideHelp:"Hide Help", ShowHelp:"Show Help"}}
//Usage e.g: alert(localResources.TrackDetail.HideHelp);
//Load Localisation values into variables so that they can be available on the client
//Note that these values are loaded asynchronously, the code in the function will not run until the call has completed.
$.getJSON('Localisation.ashx?files=TrackDetail.aspx.resx&local=true', function(data) { localResources = data});
$.getJSON('Localisation.ashx?files=Errors.resx,Strings.resx', function(data) { globalResources = data});</pre>
</div>
<div>The code on the server reads the local or global resource file and streams the contents back as a JSON formatted object. Note that I opted to roll my own JSON serialization code instead of using one of the built-in serializers.</div>
<div>
<pre style="width: 900px" class="code">
Imports System.Web
Imports System.Web.Services
Imports System.Xml
Imports System.Resources
Imports System.Reflection
Public Class Localisation
Implements System.Web.IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim files As String = context.Request.QueryString("files")
Dim local As String = context.Request.QueryString("local")
Dim isLocal As Boolean
Dim folder As String = "App_GlobalResources"
context.Response.ContentType = "text/javascript"
'Write out file as object
context.Response.Write("{")
'Determine if local resource file
If local IsNot Nothing Then
isLocal = CBool(local)
If isLocal Then folder = "App_LocalResources"
End If
If files Is Nothing OrElse files.Length = 0 Then Throw New ArgumentException("Parameter 'files' was not provided in querystring.")
Dim flag As Boolean = False
For Each file As String In files.Split(",")
If flag Then context.Response.Write(",")
Dim className As String = file.Split(".")(0)
'Write the class (name of the without any extensions) as the object
context.Response.Write(className)
context.Response.Write(":{")
'Open the resx xml file
Dim filePath As String = context.Server.MapPath("~\" & folder & "\" & file)
Dim document As New XmlDocument()
Dim flag2 As Boolean = False
document.Load(filePath)
Dim nodes As XmlNodeList = document.SelectNodes("//data")
For Each node As XmlNode In nodes
'Write out the comma seperator
If flag2 Then context.Response.Write(",")
Dim attr As XmlAttribute = node.Attributes("name")
Dim resourceKey As String = attr.Value
context.Response.Write(resourceKey)
context.Response.Write(":""")
'Write either the local or global value
If isLocal Then
context.Response.Write(HttpContext.GetLocalResourceObject(String.Format("~/{0}", file.Replace(".resx", "")), resourceKey)) 'Has to be full path to the .aspx page
Else
context.Response.Write(HttpContext.GetGlobalResourceObject(className, resourceKey))
End If
context.Response.Write("""")
'Flag that we need a comma seperator
flag2 = True
Next
context.Response.Write("}")
flag = True
Next
'End file
context.Response.Write("}")
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
End Class</pre>
</div>
</div> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com1tag:blogger.com,1999:blog-2513338198128732893.post-54939856346459055052010-01-30T10:41:00.001+00:002010-01-30T10:58:11.044+00:00jQuery, Google Closure and packing or minifying for performance?<p>One thing I love about writing jQuery plug-ins is that every line of code counts towards performance. Its like real programming again. There are lots of difference ways in which you can improve performance but one must have is reducing the size of the JavaScript that comes down the wire from the server. </p> <p>There are two options to use when reducing JavaScript file size – packing and minifying. Packing uses a compression algorithm such as gzip to physical compress the file to it’s smallest possible size, whilst a decent minifyer removes whitespace, renames variables and internal functions and removes unreachable code.</p> <p>A while ago I came across <a title="JavaScript Library Loading Speed" href="http://ejohn.org/blog/library-loading-speed/" target="_blank">this post by John Resig</a> pointing out that although packing reduces the file size, it takes longer to ultimately execute, due to the repeated unpacking process every time the script is used.</p> <p>After reading this I started using the <a title="Yahoo YUI Compressor" href="http://developer.yahoo.com/yui/compressor/" target="_blank">Yahoo YUI Compressor</a> to minify all of my plug-ins, and it worked well, typically reducing file sizes by 70% or more.</p> <p>Looking through the jQuery 1.4 release notes this week I noticed that the jQuery team have switched to <a title="Google Closure Compiler" href="http://code.google.com/closure/compiler/" target="_blank">Google Closure Compiler</a>. This really is a great tool, for example it reduced my <a title="Exclusive Checkbox plug-in" href="http://bloggingdotnet.blogspot.com/2009/03/exclusive-checkbox-jquery-plug-in.html">Exclusive Checkbox</a> plug-in to only <strike>191</strike> 211 bytes and the <a title="MapReduce plug-in" href="http://bloggingdotnet.blogspot.com/2010/01/writing-map-reduce-jquery-plug-in.html">MapReduce plug-in</a> to under 1k in size! You need to be careful when using the compiler with the advanced option (due to the possible renaming of public methods and variables), but this doesn't apply to plug-ins because of the use of a closure – perhaps this is the reason for the name of the compiler.</p> <p><em><span style="background-color: #007dc5; color: #fff"> Update </span></em>  I had to abandon the use of the Advanced option for the Exclusive Checkbox plug-in, increasing the size from 191 to 211 bytes ...</p> <p><strong>Links:</strong></p> <p><a title="Online YUI compressor" href="http://refresh-sf.com/yui/" target="_blank">Online YUI compressor</a> <br /><a title="Google Closure compiler service" href="http://closure-compiler.appspot.com/home" target="_blank">Online Google Closure compiler service</a></p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-81361861612302359252010-01-28T22:57:00.001+00:002010-01-28T23:01:39.779+00:00Simple OOXML Updated<p>Simple OOXML is a helper library that I wrote for the Open XML Format SDK 2.0 to make the creation of Open Office XML documents easier. You can modify or create any .docx or .xlsx document without Microsoft Word or Microsoft Excel or any other software (ideal for server environments).</p> <p>Version 2.1.3678 has been released over at <a href="http://simpleooxml.codeplex.com/">Codeplex</a> which works with the December CTP of the SDK.</p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-29865790881641150392010-01-28T22:39:00.001+00:002010-01-30T11:09:35.602+00:00Batch conversion of docx files to pdf<p>I recently worked on a project where we had over 50 .docx files to convert to .pdf. Now Office 2007 can do this for you, but only one file at a time. Luckily I was able to piece together some code (.net 3.5 csharp) which automated this process. Select a folder and all .doc and .docx files in the folder and any subfolder will be converted to pdf and saved with a .pdf extension.</p> <p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="pdfbatch" border="0" alt="pdfbatch" src="http://www.opencomponents.com/images/pdfbatch.png" /></a> </p> <p>You still need Office 2007 or later to do this – download the code here:</p> <p><a title="PDF Batch Converter" href="http://www.opencomponents.com/downloads/PDF Batch Converter.zip">http://www.opencomponents.com/downloads/PDF Batch Converter.zip</a></p> <p>Disclaimer: Use at own risk. No kittens were harmed during the making of this software.</p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-31675482885221435412010-01-25T23:35:00.001+00:002010-01-25T23:35:42.509+00:00MapReduce plug-in Release Candidate now available<p>The MapReduce plug-in for jQuery has been uploaded to the following url:</p> <p><a href="http://plugins.jquery.com/project/MapReduce">http://plugins.jquery.com/project/MapReduce</a></p> <p>The plug-in implements a a type of map/reduce algorithm that executes synchronously or asynchronously in the browse whilst minimising loss in performance. Supports long running operations without script timeout messages.</p> <p>Add map and reduce functions using the $.map and $.reduce methods and execute the functions using the $.execute method. Nested map and reduce functions are supported.</p> <p>The download contains two samples of finding the prime numbers in a sequence of numbers, one using a plain javascript function and one using map reduce to calculate this asynchronously without causing script timeout errors in the browser.</p> <p><b>Options</b></p> <p>The following options can be used when calling the <i>$.execute</i> method:</p> <p><i><strong>async</strong></i>: true or false - determines whether the $.execute method runs asynchronously (default false) <br /><i><strong>race</strong></i>: no of functions to call per iteration when <i>async</i> is true (default 100) <br /><i><strong>interval</strong></i>: interval in ms between iterations when <i>async</i> is true (default 1ms)</p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-74230640266444155992010-01-23T13:58:00.001+00:002010-01-30T11:01:39.110+00:00Introduction to Map Reduce using jQuery<p>(Solved: How to avoid the "A script on this page is causing Internet Explorer to run slowly." message) </p> <p>When <a title="spellayt spell checking plug-in" href="http://bloggingdotnet.blogspot.com/2009/03/creating-spell-as-you-type-jquery-plug.html">writing the spellayt spell checking plug-in</a>, I came across an interesting problem with long running JavaScript code – the browser would timeout and display a message box to the user with the text "A script on this page is causing Internet Explorer to run slowly." Even worse, the dialog gives the user the option to cancel the script, potentially breaking your page.</p> <p>The solution was to use a timer to simulate a background thread, but the solution wasn’t generic and felt far from elegant. This week, with the <a href="http://arstechnica.com/open-source/news/2010/01/googles-mapreduce-patent-what-does-it-mean-for-hadoop.ars">approval of Google’s Distributed MapReduce patent</a>, I realised that a simpler non-distributed map reduce algorithm would enable the running of code both asynchronously and over long periods of time in JavaScript without complex state management and stack issues.</p> <p>Map reduce works by taking key/value pairs and running them through a function to create intermediate key/value pairs until all the data has been processed (map). The data is then filtered (reduced) to obtain a result. Joel Spolsky (Joel on Software) has a <a href="http://www.joelonsoftware.com/items/2006/08/01.html">nice article</a> that explains the fundamentals behind map reduce. </p> <h4>Sieve of Eratosthenes</h4> <p>The Sieve of Eratosthenes is an algorithm for finding prime numbers, <a href="http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes">this Wikipedia article</a> has a  visual explanation of how it works. Its a great example of something that is processor intensive but can be broken up into smaller steps.</p> <p>A standard JavaScript implementation (using Euler’s optimisation) would look something like this:</p> <pre class="code">function eratosthenesSieve(upperBound) {
var upperBoundSquareRoot = Math.floor(Math.sqrt(upperBound), 0);
var isComposite = [];
for (var m = 2; m <= upperBoundSquareRoot; m++) {
if (!isComposite[m]) {
_primes.push(m);
for(var k = m * m; k <= upperBound; k += m) {
isComposite[k] = true;
}
}
}
for(m = upperBoundSquareRoot; m <= upperBound; m++) {
if (!isComposite[m]) _primes.push(m);
}
}</pre>
<p>The <em>isComposite</em> variable contains an array of boolean indicating whether is element is prime (false) or not (true). The <em>_primes</em> array also contains the prime numbers.
<br /></p>
<h4>Redefining the problem as a set of Map / Reduce functions</h4>
<p>The great thing about map/reduce is that once the problem is defined as a set of functions, it doesn’t matter how the map/reduce is implemented, you should always get the same results. Usually, each for loop will result in a matching <em>$.map</em> or <em>$.reduce</em> function. Reorganising the <em>eratosthenesSieve</em> function to use map reduce requires the following steps:</p>
<ul>
<li><strong><em>Map</em></strong> an array containing the initial values – in this case the index of the array is the number we are testing, and a boolean will indicate whether it is a prime or composite number. </li>
<li><strong><em>Map</em></strong> each prime up to the square root of the upper bound. For each <strong><em>Map </em></strong>that is a prime, strike out it’s square multiplied by the remaining numbers until the upper bound is reached. </li>
<li><strong><em>Reduce</em></strong> the array by totalling the number of primes (false values) left. </li>
<li>Execute the functions to return the result. </li>
</ul>
<p>The code now looks like this:</p>
<pre class="code">function eratosthenesSieve2(upperBound) {
//Create an array of booleans representing prime = false
var composites = new Array(upperBound);
//Set all to prime (false) to start
$.map(composites, function(index, value) {
return false;
});
//Calculate the sqr root of the upper bound
var upperBoundSquareRoot = Math.floor(Math.sqrt(upperBound), 0);
//For each item, calculate the non primes
$.map(composites, function(index, value) {
if (index < 2 || index > upperBoundSquareRoot) return value;
//If the array item is a prime then map all non primes
if (value == false) {
var k = index * index;
$.map(composites, function(index2, value2) {
if (index2 == k) {
k += index;
return true;
}
return value2;
});
}
return value;
});
//Count only the primes
$.reduce(composites, 0, function(index, value, result) {
if (index >= 2 && value == false) result++;
return result;
});
return $.execute();
}</pre>
<p>The first <em>$.map</em> function initialises the <em>composites</em> array. The second and third map <em>$.map </em>strikes out multiples of primes. The <em>$.reduce</em> function counts the remaining primes by accumulating the <em>result</em> variable. Note the extra work we have to do to simulate the functionality of the for loop and when we haven’t performed any processing we return the same value that was passed into the function.</p>
<p>Finally, we <em>$.execute</em> the functions. If you attach a debugger to the script, you’ll notice the functions only start executing once this method is called.</p>
<p>Download the plug-in code from the <a href="http://plugins.jquery.com/project/MapReduce">Map Reduce plug-in page</a>.</p>
<p>Next time, I’ll dive into the details of implementing the Map Reduce plug-in and the pitfalls encountered along the way.</p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-33497792663475202032010-01-23T08:10:00.001+00:002010-01-23T08:16:54.770+00:00Object Data Blocks 2.0 Release Candidate<p> </p> <p>Object Data Blocks is object persistence style ORM for new database implementations. Define you data layer using classes to define tables and fields and decorate them with attributes to define keys, indexes, constraints etc. A provider model for a specific relational database (currently sql server 2005 or later) takes care of the rest. Any changes to the assembly can be deployed at runtime seamlessly to the database without any loss of data.</p> <p>Read more information and view code samples <a title="Object Data Blocks Documentation" href="http://objectdatablocks.codeplex.com/documentation">here</a>.</p> <p>Object Data Blocks is released under the GPL 2.0 licence and is hosted at <a title="http://objectdatablocks.codeplex.com" href="http://objectdatablocks.codeplex.com">http://objectdatablocks.codeplex.com</a></p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-30516460567390701182009-10-06T22:50:00.001+01:002009-10-06T22:51:00.273+01:00Simple OOXML 2.1.3565 Released<p>Create .xlsx and .docx documents from templates or from new without Microsoft Excel or Microsoft Word. This release fixes previously reported issues and adds the following functionality</p> <ul> <li>Works with August 2009 CTP of the Open XML SDK. </li> <li><i>DeleteRow</i> and <i>DeleteRows</i> from a Worksheet </li> <li>Use FindColumn to retrieve a column from a Worksheet e.g. to set a column width. </li> </ul> <br />The following issues have been fixed <ul> <li>id# 2227 - PasteDataTable results in a corrupt .xlsx file when pasting a DataTable that contains typeof(float) columns with a CultureInfo other than "en-US" </li> <li>id# 2291 - PasteDataTable fails with adjacent existing data </li> </ul> <p> <br />Note: Download the source code to view examples and unit tests with lots of sample code.</p> <p><a title="http://simpleooxml.codeplex.com" href="http://simpleooxml.codeplex.com">http://simpleooxml.codeplex.com</a></p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-5296559938771445132009-10-06T22:47:00.001+01:002009-10-06T22:48:59.766+01:00Announcing the release of the jQuery databind plug-in<p>The databind plug-in allows you to automatically bind the contents of an object in JavaScript (usually retrieved using AJAX/JSON). </p> <p>Each key in the object is used as an id (.example) selector within the selector provided e.g.</p> <pre>var data = { title: 'Lorem ipsum', text: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' };
$(document).binddata(data);</pre>
<p><strong><body>
<br /><div>
<br /><p id="title" style="font-weight:bold"></p>
<br /><p id="text"></p>
<br /></div>
<br /></body></strong></p>
<p>Provides the output visible at <a href="http://www.opencomponents.net/databind/example1.htm">http://www.opencomponents.net/databind/example1.htm</a></p>
<p>More complicated examples include the ability to bind arrays of data and objects to tables and unbind forms into json.</p>
<p>More examples and code can be downloaded from: <a href="http://www.opencomponents.net/databind/">http://www.opencomponents.net/databind/</a></p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-50085693817175686072009-06-24T21:42:00.004+01:002009-06-24T22:29:07.034+01:00Databinding with jQuery<p>I guess the title of this blog should be "Writing a new jQuery plug-in every week" - that's all I seem to be doing right now - but I keep finding functionality that isn't available as a plug-in, or has just been plain poorly implemented.</p>
<p>I'm using jQuery UI for a web project right now, and currently it's missing the ability to turn an html table into a grid styled using the UI css. Now there are some good lightweight plug-ins out there, such as <a href="http://tablesorter.com/docs/">tablesorter</a> and I didnt want to reinvent the wheel. Nor did I want to use a heavy wieght plugin such as jqGrid that is impressive but tries to do too much, especially when what you're really only after is a styled table.</p>
<p>To this end, I'm currently workign on the <a href="http://plugins.jquery.com/project/tablegrid">TableGrid plug-in</a>, that uses the guidelines set out by the jQuery UI development team on how to style tables, whilst incorporating the work done by other developers to enable scrolling, paging, sorting etc. (<a href="http://www.opencomponents.net/tablegrid/">Example1</a>, <a href="http://www.opencomponents.net/tablegrid/page.htm">Example2</a>)</p>
<p>Which brings me to the subject of this post. I didn't agree with the mechanism used in other grid plug-ins where the data retrieval element is included inside the plug-in, to load data via ajax or some other method. What if I also wanted to load data into say my form?</p>
<p>Following my approach of a super plug-in above, I realised I would first need a data binding plug-in so that developers could load table data on-the-fly. A quick look confirmed there was nothing out there that could be used.</p>
<p><span style="font-weight:bold;">The databind plug-in</span></p>
<p><a href="http://www.opencomponents.net/databind/">View examples and download.</a></p>
<p>Use the databind plug-in to bind a json object to any html element that has text, is an input or is a table/tbody. Each key (property name) is matched to the id of an element within the target of the <span style="font-style:italic;">databind</span> function. The inner text can be used, or the value of an input element - the plug-in is smart enough to decide. Pass array or a collection of objects to the plug-in to bind rows of data to a table or table body.</p>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com1tag:blogger.com,1999:blog-2513338198128732893.post-48293874636070708902009-06-10T19:40:00.006+01:002009-06-10T19:53:59.120+01:00UpdatePanel plug-in 1.0.0 released.In a <a href="http://bloggingdotnet.blogspot.com/2009/05/introducing-updatepanel-plug-in.html">previous post</a>, I introduced a plug-in that makes it simple for developers to integrate jQuery function calls with Microsoft Ajax UpdatePanels.
The final version has been released today to both <a href="http://plugins.jquery.com/project/updatepanelplugin">http://plugins.jquery.com</a> and <a href="http://updatepanelplugin.codeplex.com/">http://www.codeplex.com</a>.
<p><span style="font-weight:bold;">Functions</span></p>
<ul>
<li>.panelCreated(fn) - called when the UpdatePanel is created on a page</li>
<li>.panelUpdated(fn) - called when the panel is updated during a asynchronous (ajax) postback.</li>
<li>.panelReady(fn) - called when the UpdatePanel is first created or updated.</li>
<li>.beginRequest(fn) - called before the processing of an asynchronous postback starts and the postback request is sent to the server.</li>
<li>.initializeRequest(fn) - called during the initialization of the asynchronous postback. Allows the cancellation of the request.</li>
</ul>
<p>The download includes the script file and a simple example.</p>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-84051629183925353842009-05-17T21:30:00.015+01:002009-05-17T22:07:15.353+01:00Getting started with the Simple OOXML library.<p>The Simple OOXML library allows you to create Word Processing (.docx) and Spreadsheet (.xlsx) documents quickly and easily, without having to understand the complex nature of the underlying Xml formats. Because the documents are (mostly) pure xml, these documents can be created in environments even where there is no Microsoft Office installation, such as on a web server.
</p><p>Whilst the Open Xml Format SDK provides a convenient object wrapper around the xml specification, it is still far from easy to create these documents. Even with a sound understanding of the specification, the Simple OOXML library tool is still useful in providing wrapper functionality to developers, without having a noticeable performance overhead.
</p><p>To use the Simple OOXML library, you need to be using .Net Framework 3.5 (or later). You'll also need to download the Open Xml Format SDK v 2.0. The current release is the April 2009 CTP and is available from the Microsoft website here: <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0">http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0</a>. Obviously this is pre-release code but so far I've found the CTP releases very stable and haven't found any problems or bugs. Finally, you will need to download a copy of the latest Simple OOXML library release, available at CodePlex: <a href="http://simpleooxml.codeplex.com/Release/ProjectReleases.aspx">http://simpleooxml.codeplex.com/Release/ProjectReleases.aspx.</a> Since Simple OOXML is open source and distributed under the LGPL licence, you can use and distribute the binary with any application, commercial or otherwise. You can also have a look at the C# code to see how the library operates.</p>
<p>To demonstrate the capabilities of the Simple OOXML library, I'll show you how a number of ways to work with Spreadsheet documents by creating a new ASP.NET Web Application in Visual Studio 2008. Follow these steps to get started:</p><ol>
<li>Create a new ASP.NET Web Application.</li>
<li>Include references to <em>DocumentFormat.OpenXml</em> from the SDK and the <em>DocumentFormat.OpenXml.Extensions.dll</em> from the Simple OOXML release.</li><li>Finally, add an asp:Button control to the <em>default.aspx</em> page that was created for you, so that we have somewhere to run our code from.</li></ol>
<p></p>
<p>Make sure that you are using the following namespaces:</p>
<pre class="code">
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using DocumentFormat.OpenXml.Extensions;
</pre>
<br/>
<p><strong>Creating a new Spreadsheet (.xlsx) document.
</strong></p>
<p>In the click event handler for the button added above, add the following code:</p>
<pre class="code">
protected void Button1_Click(object sender, EventArgs e)
{
MemoryStream stream = SpreadsheetReader.Create();
SpreadsheetDocument doc = SpreadsheetDocument.Open(stream, true);
WorksheetPart worksheetPart = SpreadsheetReader.GetWorksheetPartByName(doc, "Sheet1");
WorksheetWriter writer = new WorksheetWriter(doc, worksheetPart);
writer.PasteText("B2", "Hello World");
//Save to the memory stream
SpreadsheetWriter.Save(doc);
//Write to response stream
Response.Clear();
Response.AddHeader("content-disposition", String.Format("attachment;filename={0}", "performance.xlsx"));
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
stream.WriteTo(Response.OutputStream);
Response.End();
}
</pre>
<p>The first four lines of code create a stream containing a new document. This is loaded into a standard <em>SpreadsheetDocument</em> object. A <em>WorksheetPart</em> is then retrieved using a sheet name. Finally a <em>WorksheetWriter</em> is created to enable us to write content to the worksheet. Next, the writer is used to paste the text "Hello World" into cell reference "B2". The static <em>Save</em> method of the <em>SpreadsheetWriter </em>class is used to update the stream with the document. The final five lines write the document stream to the browser setting the correct header values for a spreadsheet document.</p><p>In the next part of this series I'll demonstrate how to add numeric values, dates, shared text and datatables to worksheet documents.</p>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com6tag:blogger.com,1999:blog-2513338198128732893.post-25338328265153723362009-05-17T21:12:00.003+01:002009-06-04T15:26:11.714+01:00Introducing the UpdatePanel plug-in.<p>A while ago I blogged about Combining jQuery and Ms Ajax UpdatePanels. (<a href="http://bloggingdotnet.blogspot.com/2009/03/combining-jquery-and-updatepanels.html">http://bloggingdotnet.blogspot.com/2009/03/combining-jquery-and-updatepanels.html</a>). The main problem is that the UpdatePanel contents (a Div element) are replaced during each post back from the server and this means that jQuery looses all the references to the elements that have now been replaced in the DOM. My initial work around (and commonly found on the internet) is a little clumsy as it involves hooking the Ms Ajax <em>pageLoad</em> event and placing all your jQuery code in a separate function which is then called from <em>$(document).ready</em> or <em>pageLoad</em>. Not pretty and not clever, especially when you have lots of jQuery and you only want to rerun the jQuery for the panel that has actually changed.
</p><p>My subsequent workarounds involved looking into the LiveQuery plug-in and looking at Live events which are new to jQuery 1.3, however I wasn't satisfied with the performance, and the code still looked ugly. And when it looks ugly that usually means there is a better way. What I wanted was code that looked and worked like any other jQuery plug-in. I needed to dig more deeply into the Ms Ajax client runtime. What I found was the PageRequestManager which is created once per page by Ms Ajax and fires the pageLoaded event on each post back. Hooking into this event allows us to examine the panels that have been updated or created. Using this information, it was then relatively straightforward to wrap a jQuery-style functional interface around these events.
</p><p>The UpdatePanel plug-in has the following three callbacks:</p><p></p><ul><li><i>.panelCreated(fn)</i> - called when the UpdatePanel is created on a page</li><li><i>.panelUpdated(fn)</i> - called when the panel is updated during a asynchronous (ajax) postback.</li><li><i>.panelReady(fn)</i> - called when the UpdatePanel is first created or updated</li></ul><p></p><p>You would generally use the panelReady event like so:</p>
<pre class="code">
$(document).ready(function() {
//Place jQuery code here for elements selected outside the update panel
$('#UpdatePanel1').panelReady(function() {
//Place jQuery code here for elements selected inside the update panel
});
});
</pre>
<p>Generally, you would only want to use panelReady, which is called when the page is first loaded, or on each postback. A sample project as well as the script is available at <a href="http://updatepanelplugin.codeplex.com/">http://updatepanelplugin.codeplex.com/</a> or <a href="http://plugins.jquery.com/project/updatepanelplugin">http://plugins.jquery.com/project/updatepanelplugin</a>
</p>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-90689054282245509392009-05-14T21:45:00.002+01:002009-05-14T21:49:19.880+01:00Simple OOXML featured on OpenXmlDeveloperSimple OOXML has been picked up by <a href="http://openxmldeveloper.org">http://openxmldeveloper.org</a> - Microsoft's website for promoting the Office Open Xml standard - and is mentioned on their home page. Expect to see an article appear on the site over the next few days.James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-87427599882827277272009-03-23T19:38:00.011+00:002010-01-30T10:18:54.491+00:00Exclusive Checkbox jQuery Plug-inWeb interfaces like Hotmail often have a checkbox or radio button next to each item so that you can select that row. I've always disliked the radio button approach as you are limited to one row at a time eg when deleting. However sometimes you'd like to keep the checkboxes but have them behave like radio buttons. I couldn't find a really simple jQuery plug-in so I decided to write one. Original and minified versions at the end of the article.  <p>(<b>Update:</b> I changed the code slightly to use the official jQuery extend function for the plug-in definition, and to include the usage in the comments.)</p> <pre class="code">/*
* Exclusive Check Plugin v1.0.2
* Copyright (c) James Westgate
*
* @requires jQuery v1.3.2
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.ph
* http://www.gnu.org/licenses/gpl.html
*
* @usage $('input:checked').exclusiveCheck();
* @usage $('form input:checked').exclusiveCheck();
* @usage $('table tbody input:checked').exclusiveCheck();
*
*/
//Create closure
(function($) {
//Plugin definition
$.fn.extend({
exclusiveCheck: function() {
var selector = $(this);
//Loop through each item in the matched set and apply event handlers
return this.each(function(i) {
//When the checkbox gets clicked, uncheck other checkboxes
$(this).click(function(event) {
var clicked = this;
//Uncheck all except current
if (this.checked) {
selector.each(function() {
if (this != clicked) this.checked = false;
});
}
});
});
}
});
// end of closure
})(jQuery);</pre>
<p><a href="http://www.opencomponents.com/downloads/ExclusiveCheck plug-in.zip">Download original and minified version.</a></p> James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com2tag:blogger.com,1999:blog-2513338198128732893.post-87361095651444927052009-03-05T21:56:00.014+00:002009-03-26T17:34:59.583+00:00Introducing the Simple OOXML library<span xmlns=""><p><span style="color:black;"><span class="Apple-style-span" style="font-size:small;">The new xml based document formats (.xlsx, .docx, .pptx etc) introduced with Office 2007 finally provided developers with the ability to create documents on a server without having to have either MS Word or Excel installed or to use a 3</span><sup><span class="Apple-style-span" style="font-size:small;">rd</span></sup><span class="Apple-style-span" style="font-size:small;"> party component.
</span></span></p><p><span style="color:black;"><span class="Apple-style-span" style="font-size:small;">However producing this Xml is very complicated and it's certainly not a pretty format. The OOXML SDK goes as far as wrapping the Xml elements of the specification into a set of .net classes, but still falls short of the higher-level functionality required to actually create documents. Some open source libraries, such as ExcelPackage, are incomplete or discontinued and I wanted to create a simple, robust fully supported library that fits right into the object model of version 2.0 of the sdk.</span></span></p><p><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;"><span style="color:black;"></span></span><span style="font-size:+0;"><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;">The </span><a href="http://simpleooxml.codeplex.com/"><span class="Apple-style-span" style="font-size:small;">http://simpleooxml.codeplex.com</span></a><span class="Apple-style-span" style="font-size:small;"> project addresses this issue by providing a layer of abstraction over version 2.0 as a set of simple classes and methods to create new spreadsheet (Excel) and word processing (Word) files with the following benefits:</span></span></span></span></p><p></p><ol><li>No Excel or Word is required on the server.</li><li>No in-depth knowledge of the OOXML standard or SDK is required.</li><li>New documents can be created or existing templates can be modified.</li><li>Ability to stream directly to the browser or between servers</li><li><span style="font-size:+0;"><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;">High perfor</span></span></span><span style="font-size:+0;"><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;">mance</span></span></span></li></ol><div>The following table outlines the classes used to create and read office open xml documents:</div><p></p><div style="TEXT-DECORATION: underline"><table style="BORDER-COLLAPSE: collapse" border="0"><colgroup><col style="WIDTH: 170px"><col style="WIDTH: 469px"></colgroup><tbody valign="top"><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">DocumentReader</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">Static functions used to create new word processing documents.
</span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">DocumentWriter</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">Static functions used to paste text items into a word processing document using bookmarks and save the document to a stream or file.</span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">SpreadsheetReader</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">Static functions to create new spreadsheet documents and to retrieve worksheet, column and row references. Get style and defined name range parts. </span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">SpreadsheetStyle</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">Create an object that can set style, color and font information in a spreadsheet and retrieve and compare style parts.</span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">SpreadsheetWriter</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">Static functions to create style parts in a spreadsheet, control shared strings and helper functions when working with spreadsheet documents</span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">WorksheetReader</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">High level and static fucntions to retrieve cell and style information from a worksheet. </span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><strong><span class="Apple-style-span" style="font-family:arial;font-size:small;">WorksheetWriter</span></strong></span></p></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><p><span style="color:black;"><span class="Apple-style-span" style="font-family:arial;font-size:small;">High level and static functions to write text, numeric and datatable based values to a worksheet. Draw borders, insert rows, merge cells and set print areas.</span></span></p></td></tr><tr><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><span class="Apple-style-span" style="font-family:arial;font-size:small;"></span></td><td style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: black 0.5pt solid"><span class="Apple-style-span" style="font-size:small;"></span></td></tr></tbody></table></div><p style="TEXT-DECORATION: underline"><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;"><span style="font-size:+0;"></span></span></span></p><span style="font-size:+0;"><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;">Simple OOXML requires version 2.0 of the OOXML SDK which can be found here:
</span></span></span></span><div><span xmlns=""><span style="font-size:+0;"><span style="font-size:+0;"><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0"><span class="Apple-style-span" style="font-size:small;">http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0</span></a><span class="Apple-style-span" style="font-size:small;">
</span></span></span></span></div><div>
</div><div><span xmlns=""><span style="font-size:+0;"><span style="font-size:+0;"><span class="Apple-style-span" style="font-size:small;">In my next series of posts, I'll show how easy and powerful this library is.</span></span></span><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0"> <p><span style="color:#30332d;"><span class="Apple-style-span" style="font-size:medium;"><span style="font-size:+0;"><span style="font-size:+0;"></span></span></span></span></p></a></span><a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=C6E744E5-36E9-45F5-8D8C-331DF206E0D0"></a></div><div><span class="Apple-style-span" style="FONT-STYLE: italic">(The DocumentFormat.OpenXml.Extensions.Testing unit test project included in the source on Codeplex contains samples of almost every type of operation supported by the library.)</span></div>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-73565715558138979752009-03-03T21:37:00.011+00:002009-05-14T08:58:25.265+01:00Creating a Spell as you type jQuery plug-in - Part 3<span xmlns=""><p>In my previous posts, I described how to create a jQuery plug-in called spellayt (Spell as you Type) that provided spelling correction to Internet Explorer users.</p><p>
<span class="Apple-style-span" style="font-weight: bold; ">The timed work queue pattern</span></p><p>The performance of initial implementations of the spellayt were disappointing, you would often wait a few seconds whilst the latest words typed in were checked and highlighted. Even worse, you could get the dreaded "A script on this page is causing Internet Explorer to run slowly." message. I soon found I needed a solution usng a multi-threaded approach so that the spell checking could happen in the background to the user typing. A quick check confirmed that JavaScript does not support more than one thread although the search did reveal some interesting options.</p><p>Because the word breaking and dictionary checks could potentially take a few seconds each, I decided that only one word could be checked against the dictionary at a time. The trick is to use lots of short functions at regular intervals, so that the UI can continue to process events from the user.</p><p>This gave me the idea for implementing the following pattern which I call the Timed Work Queue pattern. In the plug-in, a call to <em>doWordBreak()</em> starts the ball rolling when the input receives focus:</p>
<pre class="code">
//Global values
$.fn.spellayt.global = {
options: null, //plug-in options
wordQueue: new Array() //word breaking queue
};
$(this).focus(function(event) {
//Start the the word breaking queue
doWordBreak();
});
</pre>
<p><span class="Apple-style-span" style="font-size:small;">The </span><em><span class="Apple-style-span" style="font-size:small;">doWordBreak()</span></em><span class="Apple-style-span" style="font-size:small;"> function is actually really straight forward. It shifts the oldest work item off the queue and executes that item. The function then calls itself again in a predetermined time (50 ms seems to be a good figure)</span></p>
<pre class="code">
//Pops the next word off the word breaking queue
function doWordBreak() {
var g = $.fn.spellayt.global;
//Get an item off the queue
if (g.wordQueue.length > 0) {
var work = g.wordQueue.shift();
work.call(work.data);
}
//Process the next item
g.wordTimer = setTimeout(function() { doWordBreak(); }, g.options.milliseconds);
}
</pre>
<p>So what does the object look like that we are pushing onto the work queue ? The breaktext function breaks text into sentences and words, and loads words onto the queue one at a time</p>
<pre class="code">
//Check the spelling for all words in the input provided
function breakText(input) {
if (input == null) return;
//Split text into a 2d array of sentences and words
var sentences = splitWords(input.value);
if (sentences == null) return;
//Add the call to checkWord() to the work queue for each word in each sentence
for (var i = 0; i < sentences.length; i++) {
$.fn.spellayt.global.wordQueue.push({ call: function(parm) { checkSentence(parm); }, data: sentences[i] });
}
};
</pre>
<p>The object consists of a function pointer <em>call </em>and data to be passed to the function <em>data</em>. As long as your function has a single parameter (e.g. a JSON object), you could queue up any combination of functions to execute.</p><p>This is really handy as you can push completely different function pointers onto the queue, as well as putting some items ahead of others with a higher priority.</p></span>
<div><a href="http://bloggingdotnet.blogspot.com/2009/01/creating-spell-as-you-type-jquery.html">Creating a spell as you type jQuery plugin - part 1</a></div><div><a href="http://bloggingdotnet.blogspot.com/2009/02/creating-spell-as-you-type-jquery.html">Creating a spell as you type jQuery plugin - part 2</a></div>
<div>Download: <a href="http://plugins.jquery.com/project/spellayt">http://plugins.jquery.com/project/spellayt</a>
</div>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com8tag:blogger.com,1999:blog-2513338198128732893.post-62250334964936754932009-03-03T18:38:00.003+00:002009-04-21T22:30:31.055+01:00Compress ASP.NET response streamsWhen sending large amounts of data from IIS to the browser, it is sometimes worth compressing certain types of data such as text documents.
Although compression is not supported by IIS 6.0, most browsers support basic gzip compression and they notify the server of this ability by sending a header in each request.
The following piece of code shows how to use the System.IO.Compression namespace to add a filter to the output stream that compresses the output whilst checking and setting the correct headers. In this example, a .xls document containing in a string is being sent to the client:
<pre class="code" style="width:900px">
<font size=3>
'Send response with content type to display as MS Excel
context.Response.Clear()
context.Response.Buffer = True
context.Response.AddHeader("content-disposition", String.Format( "attachment;filename={0}", fileName))
context.Response.ContentEncoding = Encoding.UTF8
context.Response.Cache.SetCacheability(HttpCacheability.Private)
'Compress the output as it may be very large
'When flushing or closing+ending the stream, the compression filter does not have a chance to write the compression footer
'Therefore, make sure the compression filter stream is closed before flushing
AddCompression(context)
context.Response.ContentType = "application/vnd.ms-excel"
'Write to response
context.Response.Write(_reportXmlss)
'context.Response.Flush() 'Do not flush if using compression
'context.Response.Close()
context.Response.End()
</font>
</pre>
The <i>AddCompression</i> method checks the appropriate headers and adds a compression filter stream to the output:
<pre class="code">
<font size=3>'Add compression to the response stream
Public Sub AddCompression(ByVal context As HttpContext)
Dim acceptEncoding As String = context.Request.Headers("Accept-Encoding")
If acceptEncoding Is Nothing OrElse acceptEncoding.Length = 0 Then Return
'Convert to lower to check
acceptEncoding = acceptEncoding.ToLower
'Gzip or Compress compression
'Compress compression is quicker and performs better compression so try that first
If (acceptEncoding.Contains("deflate")) Then
context.Response.Filter = New DeflateStream(context.Response.Filter, CompressionMode.Compress)
context.Response.AppendHeader("Content-Encoding", "deflate")
ElseIf acceptEncoding.Contains("gzip") Then
context.Response.Filter = New GZipStream(context.Response.Filter, CompressionMode.Compress)
context.Response.AppendHeader("Content-Encoding", "gzip")
End If
End Sub</font>
</pre>
To check if compression is being used, I use the awesome <a href="http://www.httpwatch.com/">HttpWatch</a>, which shows useful information such as headers, amount of compression and bytes sent/received.James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com2tag:blogger.com,1999:blog-2513338198128732893.post-25137855876913010242009-03-02T21:01:00.004+00:002009-03-24T20:11:26.506+00:00Combining jQuery and UpdatePanelsSome of you may have noticed using Microsoft Ajax and jQuery together works fine until you do a post back in e.g. an UpdatePanel and the jQuery plugins referencing elements contained in the panel stop working. I believe these are the event handlers which are bound to the old DOM elements by jQuery. <div>
</div><div>A simple work around is to combine a bit of Microsoft AJAX with jQuery - in this example I rerun all my jQuery that would normally reside in <span class="Apple-style-span" style=" "><span class="Apple-style-span" style="font-size:medium;"><span class="Apple-style-span" style="font-family:'courier new';"><span class="Apple-style-span" style="font-size: small;">$(document).ready </span></span></span></span>after each ajax callback instead.</div><pre>
//Jquery document ready
$(document).ready(function(){
RunScript();
})
//This is called after every page load by ajax
//It is used instead of the normal document ready function
function pageLoad(sender, arg) {
if (arg.get_isPartialLoad()) {
RunScript();
};
}
//Main Jquery function
function RunScript() {
//... normal jQuery code here etc
</pre>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0tag:blogger.com,1999:blog-2513338198128732893.post-29887278455237915502009-02-27T10:43:00.006+00:002009-03-24T20:10:41.629+00:00Spell as you Type 1.0 plug-in releasedToday I released the Spell as you Type jQuery plug-in. It provides inline (red wavy) spell checking and correction options to Internet Explorer users - functionality that is built into every other browser.<div></div><div>Codeplex: <a href="http://openspell.codeplex.com/">http://openspell.codeplex.com/</a></div><div>Jquery: <a href="http://plugins.jquery.com/project/spellayt">http://plugins.jquery.com/project/spellayt</a>
<div>
</div><div>To use, simply call the spellayt function in jQuery</div><pre class="code">
$(document).ready(function() {
$('#txtTextarea').spellayt();
})
</pre>
<div><div>The plug-in works fully on the client side. For more information, view my series on building this plug-in:</div><div></div><div><a href="http://bloggingdotnet.blogspot.com/2009/01/creating-spell-as-you-type-jquery.html">Creating a spell as you type jQuery plugin - part 1</a></div><div><a href="http://bloggingdotnet.blogspot.com/2009/02/creating-spell-as-you-type-jquery.html">Creating a spell as you type jQuery plugin - part 2</a></div><div><a href="http://bloggingdotnet.blogspot.com/2009/03/creating-spell-as-you-type-jquery-plug.html">Creating a spell as you type jQuery plugin - part 3</a></div><div>
</div></div></div>James Westgatehttp://www.blogger.com/profile/11208670447265243900noreply@blogger.com0