JQuery for Everyone: $.grep and calcHTML Revisited
Every once in a while, good scripts need a second look. The calcHTML idea popularized by Christophe has such potential for frequent use, I decided to see if I can improve on my previous work (link).
First, I noticed that I created an unnecessary extension of jQuery with “$.calcHTML = function()…” I stopped that practice. Second, I noticed that the filter, “.filter(”:contains(<DIV)”)…” did not really find HTML in need of rendering, it found the beginnings of DIV tags.
In this updated version (tested with jQuery 1.3.1 in IE7 and FF3 with preview pane or grouping and in List View or Form), I wanted to cast a wide net to find HTML that needed rendering. To do that, I started by creating my array of elements just like before. Then I filtered the array using $.grep. The grep utility in jQuery, like the Unix function, finds things quickly in large data sets.
Of the original arrayList, I only returned items with text matching the regular expression “/<[^<]+?>/” back into arrayList. That one line of code does a lot but runs very quickly. Overall, this current script runs on my test page in 36ms (about 10ms slower than Christophe’s POJ version) — but because this script casts a wider net, we have more flexibility in our calculated columns.
For instance, instead of wrapping a link tag in a DIV, I can just use the formula:
="<a href='"&[url_field]&"'>"&[Title]&"</a>"
<script type="text/javascript"> if(typeof jQuery=="undefined"){ var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/"; document.write("<script src='",jQPath,"jquery.min.js' type='text/javascript'><\/script>"); } </script> <script type="text/javascript"> function calcHTML() { /* Add or replace the following selectors to the arrayList variable New groups are added by comma: Example: var arrayList = $("td.ms-vb,td.ms-vb2"); td.ms-vb = Data View Web Part td.ms-vb2 = List View Web Part td[id='SPFieldCalculated'] = Standard Form Calc Column td.ms-stylebody = Boxed View Styles td.ms-formbody = Standard Form td.ms-cal-monthitem a = Calendar Month table.ms-cal-tweekitem a = Calendar Week */ var arrayList = $("td.ms-vb2"); arrayList = $.grep(arrayList, function(e,i){ return ($(e).text().match(/<\;.+?>\;|<.+?>/)); }); $.each(arrayList, function(i,e){ $(e).html($(e).text().replace(/<(.+?)>/g,'<$1>')); }); } function ExpGroupRenderData(htmlToRender, groupName, isLoaded) { $("#tbod"+groupName+"_").attr("isloaded",isLoaded).html(htmlToRender).show("fast",calcHTML()); } $(function() { calcHTML(); if (typeof showpreview1=='undefined') { return; }else{ $("td.ms-vb-title").bind("mouseover", function(){ showpreview1(this); calcHTML(); }); } }); </script>
Second version (tested cross-browser with many different views of data):
<script type="text/javascript"> if(typeof jQuery=="undefined"){ var jQPath="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/"; document.write("<script src='",jQPath,"jquery.min.js' type='text/javascript'><\/script>"); } </script> <script type="text/javascript"> function calcHTML() { var arrayList = $("table.ms-listviewtable").find("td") .add("td.ms-vb") .add("td[id='SPFieldCalculated']") .add("td.ms-stylebody") .add("td.ms-formbody") .add("td.ms-cal-monthitem a") .add("td.ms-cal-defaultbgcolor a") .add("table.ms-cal-tweekitem a") ;//comment out unused lines above for better performance arrayList = $.grep(arrayList, function(e,i){ return ($(e).text().match(/<\;.+?>\;|<.+?>/)); }); $.each(arrayList, function(i,e){ $(e).html($(e).text().replace(/<(.+?)>/g,'<$1>')); }); } function ExpGroupRenderData(htmlToRender, groupName, isLoaded) { $("#tbod"+groupName+"_").attr("isloaded",isLoaded).html(htmlToRender).show("fast",calcHTML()); } $(function() { calcHTML(); if (typeof showpreview1=='undefined') { return; }else{ $("td.ms-vb-title").bind("mouseover", function(){ showpreview1(this); calcHTML(); }); } }); </script>
Update: 2009-03-04
I updated the selector to include the title link on calendar views.
Update: 2009-03-05
I updated the selector to include the cells of a Data View Web Part and the current day of a calendar web part.
Update: 2009-03-05
On second thought. All of the additional selectors for every various possibility started to slow things down. I did adjust the regular expressions to replace HTML-encoded data but I’ll have to post another article about that and how we might use it.
If you have a case other than the List View Web Part, check the chart for your situation and make the appropriate change to the arrayList selector. If you have a custom theme or custom web part, you may have to do your own searching within the DOM.
Again, this version fits the original intent which was to test on List Views.
The second version will run slower (because it’s looking for more objects) but seems to fit more of the wild variations people create out of an htmlCalc column. To speed up the second version, you can comment out the lines starting with .add that you aren’t using. See version one’s list of known references. If you find new ones, please comment here. Thanks.
- JQuery for Everyone: Accordion Left Nav
- JQuery for Everyone: Print (Any) Web Part
- JQuery for Everyone: HTML Calculated Column
- JQuery for Everyone: Dressing-up Links Pt1
- JQuery for Everyone: Dressing-up Links Pt2
- JQuery for Everyone: Dressing-up Links Pt3
- JQuery for Everyone: Cleaning Windows Pt1
- JQuery for Everyone: Cleaning Windows Pt2
- JQuery for Everyone: Fixing the Gantt View
- JQuery for Everyone: Dynamically Sizing Excel Web Parts
- JQuery for Everyone: Manually Resizing Web Parts
- JQuery for Everyone: Total Calculated Columns
- JQuery for Everyone: Total of Time Differences
- JQuery for Everyone: Fixing Configured Web Part Height
- JQuery for Everyone: Expand/Collapse All Groups
- JQuery for Everyone: Preview Pane for Multiple Lists
- JQuery for Everyone: Preview Pane for Calendar View
- JQuery for Everyone: Degrading Dynamic Script Loader
- JQuery for Everyone: Force Checkout
- JQuery for Everyone: Replacing [Today]
- JQuery for Everyone: Whether They Want It Or Not
- JQuery for Everyone: Linking the Attachment Icon
- JQuery for Everyone: Aspect-Oriented Programming with jQuery
- JQuery for Everyone: AOP in Action - loadTip Gone Wild
- JQuery for Everyone: Wiki Outbound Links
- JQuery for Everyone: Collapse Text in List View
- JQuery for Everyone: AOP in Action - Clone List Header
- JQuery for Everyone: $.grep and calcHTML Revisited
- JQuery for Everyone: Evolution of the Preview
- JQuery for Everyone: Create a Client-Side Object Model
- JQuery for Everyone: Print (Any) Web Part(s) Plugin
- JQuery for Everyone: Minimal AOP and Elegant Modularity
- JQuery for Everyone: Cookies and Plugins
- JQuery for Everyone: Live Events vs. AOP
- JQuery for Everyone: Live Preview Pane
- JQuery for Everyone: Pre-populate Form Fields
- JQuery for Everyone: Get XML List Data with OWSSVR.DLL (RPC)
- Use Firebug in IE
- JQuery for Everyone: Extending OWS API for Calculated Columns
- JQuery for Everyone: Accordion Left-nav with Cookies Speed Test
- JQuery for Everyone: Email a List of People with OWS
- JQuery for Everyone: Faster than Document.Ready
- jQuery for Everyone: Collapse or Prepopulate Form Fields
- jQuery for Everyone: Hourly Summary Web Part
- jQuery for Everyone: "Read More..." On a Blog Site
- jQuery for Everyone: Slick Speed Test
- jQuery for Everyone: The SharePoint Game Changer
- JQuery For Everyone: Live LoadTip
Great job Paul!
Now the only thing I miss is this jquery to work with calendar views.
Well that is not all true I do wish I had some jquery understanding as well, but for now I have to stick with what you guys deliver and I am truly impressed!
Are you planning on getting this to work for calendar views as well, Paul?
Thanks a lot!
/niax
Thanks for the idea. I updated the script to support calendar views. Let me know how your testing goes.
~Paul
Coincidence…I was just checking out the grep() function this week. I was not convinced that it would bring any improvement in this case. What is the benefit of grep() here, compared to a standard selector?
Paul, I also tested your script in a calendar with an “advanced” use case and it didn’t work. I’ll send you the formula I used.
@Christophe
Grep seems to be a very efficient way to reduce an array facing an expensive process.
By using grep, I was able to remove any logic from my function that applies the DOM manipulation.
Since DOM manipulation is usually a more expensive operation, I wanted to only process the required records.
Definitely send me the test case, I had never thought of using calcHTML in a calendar view before last night.
In the first link of your post you’ll find all the tutorials related to the HTML calculated column.
The most frequent request for calendars is color coding, but there are other applications.
The latest addition is the use of the method to write scripts. The next step in the series will be – as you could expect: “using calculated columns to write jQuery”!
Hi Paul,
I tried the updated version as well in a calender view, but did not succeed.
/niax
@niax
Are you using the default theme/template/css?
What formula did you use?
What exactly failed?
I updated the selector to include cells from a DVWP and current month calendar day.
Today’s updates come with a lot of testing help from Peter Allen. This should show better results in IE than the previous version.
For some reason, IE only found 77 of the 112 elements on the test page so I had to alter the selector method to use .add. I didn’t notice any speed difference so I left both versions in this post.
If you’re not sure which one to use, start with version 2.
Thanks,
Paul
Version 2 worked for my test.
btw the first version has a dummy jQPath, I was wondering if you did this on purpose.
@Christophe
Thanks for catching that, I fixed it.
Sorry for my late response, Paul!
I tested the second version as well, and it worked quite well, thank you!
On that page I also had PlanetWilsons Coulor Calendar, and it stoped working, if any one is intrested to know. I didn’t dig any further in the matter to try to work things out.
I am trying to combine both your calcHTML() and collapseText() so that my Lists can contain blocks and have the ability to collapse and expand large multiline text fields. Since each has their own version of ExpGroupRenderData() I was not able to figure out how to support both in the same script.
@Detlef,
I have a few articles coming out this week which might help. One about an abbreviated AOP script which works very nicely and another about jQuery plugins that return /this/ (which allows the chaining of methods).
Is there any way to replace the Links in a SharePoint Monthly/Weekly/Daily Calendar View to point to a Custom page?
For example –
If there is a Calendar on a SharePoint page the detail page usually is –
/Lists/MyCalendar/DispForm.aspx?ID=2
I want to replace this link with something like –
/pages/EventDetails.aspx?itemid=2
How to do this with JQuery, your help will be greatly appreciated. Thanks!
Hi Paul:
I have a squirrely formula that wraps up minutes (numbers) into a time format:
=TEXT(TIME(0,Minutes,0),”HH:MM”)
Thus far, I cannot seem to get any HTML calculated column code to work. And yes, I am grouping by a field called [Month].
Any ideas?
Thanks-Charlie Epes
Buffalo, NY
@Vijay,
To do this with jQuery (not sure if that’s the best long term solution), find the links: $(”a[href*='/Lists/MyCalendar/DispForm.aspx?ID=']“), then iterate over the group using $.each(). While you do that, perform a RegEx replace on the href attribute.
@Charlie,
That formula does not have any HTML in it, what is it that you need to appear as HTML?