Archive for category DPS911
v1.0 Release Complete
Posted by Sid in DPS911, Mercurial Project, Open Source on April 24th, 2009
Well this is it guys. My last release for the open source course is finished! It has come at the right time too as this is my 100th blog post. So for this release I ended up doing quite a bit more than I originally planned to. It all kind of became hectic in the end because ted suddenly reviewed my OnScroll patch yesterday, which meant that I immediately had to fix the changes he outlined.
First of all I tackled the files touched patch. Jorendorff has mentioned a few times that it is important to show information in an unobtrusive manner. Now, this wasn’t being accomplished earlier and so I decided to put expand/collapse functionality for the files touched.
Next I tackled a new bug where I only wanted >5 merges to get expand/collapse functionality. Anything less than that should be left as it is. I’ve got that working now.
As I mentioned earlier, I also tackled the OnScroll patch. Over the course of these last eight months this has been the patch that I’ve worked on the most. In this release I’ve done a major rehaul. The client-side code looks very different now as I had to change it to work with the new hg_templates/pushlog.tmpl. Also, I’ve used a lot of jquery to make the code shorter and simpler. Furthermore, I’ve improved bug functionality even further and got the “To Local” link to work with the new entries that load on scroll. These were the goals that I had originally set out to meet and I’ve accomplished them
Now, as I said earlier ted, djc and Pike all gave me some feedback yesterday regarding my OnScroll patch. Thus, I had to make some last minute changes to my release. First of all I tackled a problem with the server side code that handles merges. Previously I was using a long string delimited by a random separator. Now, I’ve replaced that with a nice and simple dictionary data structure. This took a bit of time as I had to rehaul major parts of my client-side implementation so that it could properly read the data that was now being stored in dictionaries.
Furthermore, I moved all my JavaScript code to an external file since the amount of code was just getting to be too much to handle in script tags. I also changed how I deal with the parity counter and how I retrieve the maximum number of entries in the database. Lastly, I made a change in regards to pushlog queries. Beforehand, my code was causing more entries to load even when a user executed a query. That should not have been happening and now I’ve managed to fix that problem.
The following are the important links from this release:
- Goals
- Expand/collapse for files touched
- Expand/collapse only for >5 pushes in a merge
- Fixing OnScroll to work with the new version of hg_templates and using more jquery functionality
- Getting the Localize Dates Link Working with the New Entries Loaded On Scroll
- Further Improving Bug Functionality for the OnScroll Patch
- Changing the Data Structure that Handles Merges for the OnScroll Patch
- Moving to an external Js file, the parity counter, retrieving max entries and dealing with pushlog queries
Finally, the release is done! All the patches have been posted to their respective bug pages. Please view the project page for more information.
v1.0 Release - Various Changes to Improve the OnScroll Patch
Posted by Sid in DPS911, Mercurial Project, Open Source on April 24th, 2009
Yesterday, ted reviewed my onScroll patch and and he outlined some changes that I should look to make. Lets dive in right away and have a look at what I have changed according to his recommendations:
Move javascript to an external file
ted recommended that I move all my JavaScript to an external file since the amount of lines was just too much. Having all that code in the script tags is not ideal. Thus, I’ve now moved all my JavaScript code to an external file leaving only the following in hg_templates/pushlog.tmpl:
var start = 0; if(window.top.location.search.substring(1) == "") fillPage({max}); $(window).scroll(function() { if(start > 0) { if($(window).scrollTop() == $(document).height() - $(window).height()) { loadEntries(1); } } });
Change the parity counter
I’ve also changed how I deal with the parity counter which is responsible for setting up the class of each row. In the pushlog the class value of the rows alternates between ‘parity0′ and ‘parity1′. Beforehand I was using an if/else block to replicate this functionality for the new entries loaded on scroll. However, this has now been changed to the following which is a better implementation:
var row = $(document.createElement('tr')); row.addClass('parity' + counter % 2); counter++;
So basically if the counter is an odd value counter % 2 will return 1, otherwise it will return 0. For each row I increment the counter by 1, which means that it alternates between an even and odd value.
Change how max entries is retrieved
ted was wondering why I was doing the following to retrieve the total amount of entries in the database:
<div id="page_header" class="page_header" maxentries="#max#">start = ($("#page_header").attr("maxentries")) - 10;
I know that the above implementation was a very round about way of doing this. In my earlier implementations I had tried doing what he recommended, which is to just declare var start = {max} but for some odd reason that didn’t work for me initially. I tried this again today and now somehow it works. This had me very confused and frustrated. I thought a bit harder about this oddity and realized that what I had probably tried beforehand was this: var start =’{max}’ which sets start to an empty string. Anyways, I’ve rectified the situation and now I do the following to set the value of the ’start’ variable:
fillPage({max});
function fillPage(max) { start = max - 10; var vHeight = 0; if (document.documentElement) vHeight = document.documentElement.clientHeight; else vHeight = document.body.clientHeight; if (document.body.offsetHeight < vHeight) { for(var count = 0, offSetHeight = document.body.offsetHeight; offSetHeight < vHeight; count++) offSetHeight += 180; if(count > 0) loadEntries(count); } }
OnScroll should not work with any pushlog queries
ted brought up a very good point in one of his comments on the bug page. He asked what would happen if a user ran a query? Would the pushlog try to load more entries even though the user just wants to see his query data? Well, for my previous implementation the answer was yes. The function fillPage() would get called when the query is loaded and it would try to load more entries. I needed to fix this situation and I did so by adding the following code:
if(window.top.location.search.substring(1) == "") fillPage({max});
window.top.location.search.substring(1) will return an empty string if no query has been executed. Thus I can just perform a simple if statement to check whether the pushlog is being loaded normally or is a query being executed. If it happens to be the former then fillPage() is called, otherwise it isn’t.
v1.0 Release - Changing the Data Structure that Handles Merges for the OnScroll Patch
Posted by Sid in DPS911, Mercurial Project, Open Source on April 23rd, 2009
Today ted unexpectedly reviewed my onScroll patch. Now, suddenly I have a ton of changes that I have to make and my release is due tomorrow (technically today since the clock just hit midnight).
One of the problems that ted focused on was how I passed merge changesets from the server-side to the client-side. I was using a weird and ugly string which is delimited by a random separator. I’ve known all along that this was a very ugly solution. When I had come up with this implementation I didn’t know python very well and thus did not use the dictionary data structure, which is an integral part of the language. I don’t know why I haven’t changed this implementation until now. I guess I decided to give other things more priority because although the solution was ugly, it worked.
Nonetheless, I have made the appropriate changes and the following is what my server-side solution looks like now:
1 2 3 4 5 | def getMergeData(ctx, mergeData): for cs in ctx.parents(): mergeData.append({'node': ctx.hex(), 'user': clean(person(cs.user())), 'desc': clean(cs.description())}) if len(cs.parents()) > 1: getMergeData(cs, mergeData) |
The client side implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | function loadEntries(iterations) { for(var t = 0; t < iterations; t++) { var end = start; $('.loader').html('<img src="static/ajax-loader.gif" align="right" />'); start -= 20; $.get('/json-pushes?startID=' + start + '&endID=' + end, function(responseText) { var pushData = JSON.parse(responseText), counter = 0; for(var i = end; i > start; i--) { var row = $(document.createElement('tr')); row.addClass('parity' + counter % 2); counter++; // user column $('<td>' + pushData[i].user + '<br /><span class="date">' + pushData[i].formattedDate + '</span></td>') .appendTo(row) .width(184); // rev column $('<td>' + createRevTd(pushData[i].individualChangeset) + '</td>').appendTo(row); // author and description column $('<td>' + '<strong>' + pushData[i].author + ' &mdash ' + createBuglink(pushData[i].desc) + '</strong>' + '</td>').appendTo(row); $('.loader').html(""); $('.titlePush').append(row); //Check whether it is a merge changeset or not if(pushData[i].mergeData != []) { for(var j = 0; j < pushData[i].mergeData.length; j++) { if(pushData[i].mergeData[j] != "") { var node = pushData[i].mergeData[j]['node']; var user = pushData[i].mergeData[j]['user']; var desc = pushData[i].mergeData[j]['desc']; createMergeRows(node, user, desc, row); // nested lists if(pushData[i].mergeData[j] instanceof Array) { for(var k = 0; k < pushData[i].mergeData[j].length; k++) { node = pushData[i].mergeData[j][k]['node']; user = pushData[i].mergeData[j][k]['user']; desc = pushData[i].mergeData[j][k]['desc']; createMergeRows(node, user, desc, row); } } } } } } }); } } |
So, as you can see now I’m using a list that holds a bunch of dictionaries. Each dictionary has 3 keys: node, user and desc. I pass the the list, mergeData over the to the client side via JSON. Then on the client side I go through the list and retrieve the values of each key (lines 29-32)
However, you must have noticed that the client-side implementation has a nested for loop (line 38). Ted was wondering why it takes a maze of nested loops to display merges (although now it is down to only one nested loop). The reason I have to do it this way is because sometimes mergeData can contain nested lists. Especially when dealing with large merges that tracemonkey usually has.
So there you have it. I’ve replaced the long and ugly string that previously held merge information with a nice and beautiful dictionary.
v1.0 Release - Further Improving Bug Functionality for the OnScroll Patch
Posted by Sid in DPS911, Mercurial Project, Open Source on April 23rd, 2009
In my earlier blog post I outlined that I wanted to further improve bug functionality for the OnScroll patch. Bugs that were only 5 digits long were not being converted into proper links. For example bug 12345 or b#12345 or 12345. I was only covering bugs that were 6 digits in length. The following is my old bug regexps:
1 2 3 | re = new RegExp("[bB][uU][gG]\\s\\d\{6\}"); re2 = new RegExp("b=\\d\{6\}"); re3 = new RegExp("\\d\{6\}\\W"); |
Now have a look at my new bug regexes:
1 2 3 | re = new RegExp('[bB][uU][gG]\s\d\{5,}'); re2 = new RegExp('b=\d{5,}'); re3 = new RegExp('\d{5,}\W'); |
As you can see the regexp implementation hasn’t changed very much. The only change was that ‘6′ became ‘5,’ and now the 5 digit bugs are converted into bug links properly. Basically ‘5,’ specifies that anything >=5 digits should be converted into bug links. Furthermore, 7 digit bugs will start to appear eventually (if they haven’t already, not sure). This implementation automatically takes care of that situation.
Another thing you will notice in my new implementation is that the regexps no longer use double quotes. Instead, I’m now using single quotes which means that I don’t need to use the double backward slash as an escape character.
v1.0 Release - Getting the Localize Dates Link Working with the New Entries Loaded On Scroll
Posted by Sid in DPS911, Mercurial Project, Open Source on April 22nd, 2009
One of my goals for this release was getting the localize dates link working with the new entries loaded on scroll. This wasn’t happening beforehand. Only the entries that were displayed with the initial page load worked with the localize dates link.
I examined why this was happening by looking at how the dates are localized. The following is the code for this functionality:
14 15 16 17 18 19 20 21 | // add click handler to the localize dates link $('#localize').show().click(function () { $(this).hide(); $('.date').each(function (i) { $(this).text(new Date($(this).text()).toLocaleString()); }); return false; }); |
As you can see above when the localize date link is clicked the function goes through each element that has a class called ‘date’ and transforms the text within the element to a local date string via toLocalString(). Now my problem was that none of the new entries loaded on scroll have any elements that contain a class called ‘date’. Thus, none of the dates for the new entries got translated into their local versions.
In order to rectify this situation I decided to make the following change within loadEntries():
77 78 79 80 | // user column $('<td>' + pushData[i].user + '<br /><span class="date">' + pushData[i].formattedDate + '</span></td>') .appendTo(row) .width(184); |
So basically now I put the date text within a a span. This span has a class called ‘date’ thus when the To Local link is clicked it will go through all the elements that have the class date, which now includes the new entries. There we have it, problem fixed!
v1.0 Release - Fixing the OnScroll Patch to Work with the New Version of hg_templates
Posted by Sid in DPS911, Mercurial Project, Open Source on April 22nd, 2009
In my earlier blog post I outlined my plan to update my OnScroll patch to work with the new version of hg_templates, which was updated recently. Now, it has access to the jquery library, which can be used to do more fun stuff. I was using jquery beforehand too but now I’ve decided to take it a step further and take advantage of jquery even more. I believe by doing this I can significantly reduce the number of lines of code and still retain the same functionality.
The Old Code
For comparisons purposes I’ve posted the old code below:
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | function loadEntries(iterations) { for(var t = 0; t < iterations; t++) { var loader = document.getElementById("loader"); var end = start; var req = new XMLHttpRequest(); loader.innerHTML = '<img src="{url}static/ajax-loader.gif" align="right" />'; start = start - 20; req.open('GET', '/json-pushes?startID=' + start + '&endID=' + end, true); req.onreadystatechange = function() { if(req.readyState == 4) { if(req.status != 404) { var pushData = JSON.parse(req.responseText), counter = 0; //var counter = 0; for(var i = end; i > start; i--) { var row = document.createElement("tr"); if(counter == 0) { row.className = "parity0"; counter = 1; } else { row.className = "parity1"; counter = 0; } var userCol = document.createElement("td"); var revCol = createRevTd(pushData[i].individualChangeset); var bugLink = createBuglink(pushData[i].desc); var authDescCol = document.createElement("td"); userCol.width = "184px"; userCol.innerHTML += pushData[i].user + '<br />' + pushData[i].formattedDate; authDescCol.innerHTML += '<strong>' + pushData[i].author + ' &mdash ' + bugLink + '</strong>'; row.appendChild(userCol); row.appendChild(revCol); row.appendChild(authDescCol); loader.innerHTML = ""; document.getElementById("titlePush").appendChild(row); //Check whether it is a merge changeset or not if(pushData[i].MergeData != []) { for(var j = 0; j < pushData[i].mergeData.length; j++) { if(pushData[i].mergeData[j] != "") { var mergeStr = pushData[i].mergeData[j]; for(var k = 0; k < pushData[i].mergeData[j].length; k++) { if(pushData[i].mergeData[j] instanceof Array) { var actualMergeStr = mergeStr[k].split('|-|'); var mergeRev = actualMergeStr[0]; var mergeUser = actualMergeStr[1]; var mergeDesc = actualMergeStr[2]; } else { var actualMergeStr = mergeStr.split('|-|'); var mergeRev = actualMergeStr[0]; var mergeUser = actualMergeStr[1]; var mergeDesc = actualMergeStr[2]; k = pushData[i].mergeData[j].length; } if(mergeDesc != pushData[i].desc) { var mergeRow = document.createElement("tr"); var mergeUserCol = document.createElement("td"); var mergeRevCol = createRevTd(mergeRev); var merge_bugLink = createBuglink(mergeDesc); var mergeAuthDescCol = document.createElement("td"); mergeRow.className = row.className; mergeUserCol.width = "184px"; mergeAuthDescCol.innerHTML += '<strong>' + mergeUser + ' &mdash ' + merge_bugLink + '</strong>'; mergeRow.appendChild(mergeUserCol); mergeRow.appendChild(mergeRevCol); mergeRow.appendChild(mergeAuthDescCol); document.getElementById("titlePush").appendChild(mergeRow); } } } } } } } } } req.send(null); } } function createRevTd(rev) { var td = document.createElement("td"); td.innerHTML += '<a href=\"/rev/' + rev.substring(0, 12) + '\">' + rev.substring(0, 12) + '</a>'; return td; } |
The New Code
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | function loadEntries(iterations) { for(var t = 0; t < iterations; t++) { var end = start; $('.loader').html('<img src="{url}static/ajax-loader.gif" align="right" />'); start -= 20; $.get('/json-pushes?startID=' + start + '&endID=' + end, function(responseText) { var pushData = JSON.parse(responseText), counter = 0; for(var i = end; i > start; i--) { var row = $(document.createElement('tr')); if(counter == 0) { row.addClass('parity0'); counter = 1; } else { row.addClass('parity1'); counter = 0; } // user column $('<td>' + pushData[i].user + '<br /><span class="date">' + pushData[i].formattedDate + '</span></td>') .appendTo(row) .width(184); // rev column $('<td>' + createRevTd(pushData[i].individualChangeset) + '</td>').appendTo(row); // author and description column $('<td>' + '<strong>' + pushData[i].author + ' &mdash ' + createBuglink(pushData[i].desc) + '</strong>' + '</td>').appendTo(row); $('.loader').html(""); $('.titlePush').append(row); //Check whether it is a merge changeset or not if(pushData[i].MergeData != []) { for(var j = 0; j < pushData[i].mergeData.length; j++) { if(pushData[i].mergeData[j] != "") { var mergeStr = pushData[i].mergeData[j]; for(var k = 0; k < pushData[i].mergeData[j].length; k++) { if(pushData[i].mergeData[j] instanceof Array) { var actualMergeStr = mergeStr[k].split('|-|'); var mergeRev = actualMergeStr[0]; var mergeUser = actualMergeStr[1]; var mergeDesc = actualMergeStr[2]; } else { var actualMergeStr = mergeStr.split('|-|'); var mergeRev = actualMergeStr[0]; var mergeUser = actualMergeStr[1]; var mergeDesc = actualMergeStr[2]; k = pushData[i].mergeData[j].length; } if(mergeDesc != pushData[i].desc) { var mergeRow = $(document.createElement('tr')).addClass(row.attr('class')); $(document.createElement('td')).appendTo(mergeRow).width(184); $('<td>' + createRevTd(mergeRev) + '</td>').appendTo(mergeRow); $('<td>' + '<strong>' + mergeUser + ' &mdash ' + createBuglink(mergeDesc) + '</strong>' + '</td>').appendTo(mergeRow); $('.titlePush').append(mergeRow); } } } } } } }); } } function createRevTd(rev) { return '<a href=\"/rev/' + rev.substring(0, 12) + '\">' + rev.substring(0, 12) + '</a>'; } |
As you can see above is the new code. Lots of changes to look at it. First of all the JavaScript code has been shifted within $document.ready(). The major changes have occurred in loadEntries(). The jquery library makes it extremely simple to retrieve an object by its class or id name. Instead of having to use document.getElementbyId() I can use $(’<class_name>’). I’ve used this way extensively throughout my new implementation. Furthermore, I don’t need to use document.createElement() anymore either. I can just use the $(’<html>’) syntax to create an element (e.g. line 84). Another great little change is how jquery creates an xmlHttpRequest(). The syntax is so much simpler. Only a simple $.get(url, function(responseText) {} ) is needed (line 65). Another little quirk that makes jquery awesome can be seen on lines 78-80. I can create the new element, append it to another element and change its attributes all in one go.
One important thing to note, however, is that some things didn’t change much at all. Such as the string manipulation functionality found at lines 88-107. All in all the end result of all these changes is that I have manged to reduce the total number of lines by 19. On top of that I have also added 2 extra pieces of functionality (I’ll be discussing them in future posts) without having to add any additional lines of code. A very good result, in my opinion.
v1.0 Release - Expand/Collapse for the Files Touched Patch
Posted by Sid in DPS911, Mercurial Project, Open Source on April 20th, 2009
In my goals blog post I stated that I wanted to add expand/collapse functionality to the files touched patch. Why you ask? Well the whole goal is to get the pushlog to show more information but in an unobtrusive manner. Right now this isn’t happening. Adding expand/collapse functionality will allow the user to decide when he wants to see the files and when he doesn’t.
I recently wrote a white paper on the ergonomics of touch screens. One thing that I learnt from that exercise is that it is the application’s job to adapt to the user and not the other way around. The application will not succeed if the user is forced to adapt to the application. I think this concept applies to this situation where the pushlog provides the user the ability to hide or show the files touched instead of always showing them, which forces the user to adapt to the new look of the pushlog.
The Implementation
The map file
pushlogentry = '<tr class="parity#parity# #hidden# id#id#"><td>#push%pushinfo#</td><td class="age"><a href="{url}rev/#node|short#{sessionvars%urlparameter}">#node|short#</a></td><td><strong class="filerow">#author|person# — #desc|strip|escape|buglink#</strong><span class="filetouch fileid#id#">{filesTouched}</span> <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}</span>#mergerollup%mergehidden#</td></tr>\n'
pushlog.tmpl
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | // hide files touched $('.filetouch').hide(); // Add expand/collapse link $('.filerow').each ( function(i) { if($(this).next().html() != "") { var pushid = ($(this).next().attr("class")).match(/fileid\d+/); $(this).html($(this).html() + "<br/><span class=\"filelink\">hidden files <a class=\"expandfile fileid" + pushid + "\" href=\"#\">[Expand]</a></span>"); } }); // add click handler to unhide hidden things $('.expandfile').click(function () { if ($(this).text() == "[Expand]") $(this).text("[Collapse]"); else $(this).text("[Expand]"); var pushid = $(this).attr("class"); pushid = '.' + pushid.match(/fileid\d+/); $(pushid).toggle(); return false; }); |
The above pushlog.tmpl code is placed inside $(document).ready(). As you can see I basically hide all the files touched data on line 40. Then, I go through each files touched span and create the appropriate expand/collapse link on line 42. Lastly, I have the click handler that is responsible for displaying or hiding the files touched span. One important thing to note is that I must have a unique id (”fileid” in this case) for each expand/collapse link so that I know which files touched span to toggle. Without this unique id clicking on any one link would cause all links to expand/collapse, which we obviously don’t want.

There we have it, a nice and easy solution to this problem.
v1.0 Release Goals
Posted by Sid in DPS911, Mercurial Project, Open Source on April 18th, 2009
It’s that time now, time for my last release for the open source course at Seneca. I can’t believe how fast time has gone by. It just feels like yesterday that I had started out in the first version of the course and now it’s all almost over. Anyway, I’ll leave the reminiscing for later. Lets take a look at what my plans are for this release.
I will be revisiting one of my larger bugs. I’ll look to re-write the client-side code to make it compatible with the current version of hg_templates. Furthermore, I want to change the current code to take advantage of jquery and make the localize dates link work with the new entries loaded onScroll. Also, I want to improve the bug link functionality so that bugs that only have 5 digits in them are properly converted into links. Next, I’ll look to add expand/collapse functionality to the files touched bug and take on a new bug. All in all quite a lot to do. The following are my goals for this release:
- Load more entries on scroll - Make onScroll functionality work with the new hg_templates/pushlog.tmpl, re-write code to use jquery, make the localize dates link work with all new entries loaded on scroll and Improve bug functionality
- Add expand/collapse to files touched
- Fix expand/collapse functionality for merges (new bug) - Expand/collapse functionality should only be added to merges that contain >5 pushes
Well, there’s some hard work ahead and I need to work fast because I have exams next week as well so my work will have to be efficient. However, I’m sure that I will be able to manage this situation. Only one more week to go and then my time at Seneca will come to an end. Four years gone in the blink of an eye, amazing!
Please navigate to the project page for more details.
v0.9 Release Complete
Posted by Sid in DPS911, Mercurial Project, Open Source on April 12th, 2009
All the goals for my v0.9 release have been accomplished and thus another release comes to an end. Looking back I ended up using quite a bit of jquery to fix my bugs. In the process I learnt some new things about the library that I didn’t know beforehand, such as how $(document).ready() works. The guys over at jquery have definitely done some good work.
Files touched
This patch had bitrotted as the pushlog had gone through a variety of changes since I had submitted it way back in 2008. Now, it is up to date and raring to go. I will most probably have another iteration for this patch though, where I add expand/collapse functionality to it. Although, I’ll have to get clearance from ted first though.
Changeset UI
Ted gave me an r- review since he didn’t like that I was removing what the user had entered in the text boxes if another item was selected from the drop down list. Also, he wanted the drop down list to remember which query type was last executed. I’ve managed to get both these features working and I also altered the code to take advantage of jquery, which is now available in hg_templates.
Line breaks turned into spaces
This was the new bug that I tackled this release. First of all I wanted to keep the line breaks instead of have them turned into spaces. I managed to do that. Next, I had to implement expand/collapse functionality for any commit messages that had more than one line break. Since I had experience doing this with another bug; I quickly managed to get this functionality working.
The following are the important links for this release:
- Goals
- v0.9 Release - Updating the Files Touched Patch
- v0.9 Release - Implementing changes to the Changset Query UI
- v0.9 Release - Contemplating the Implementation for the Line Break bug
- v0.9 Release - Fix for the Line Break bug
The patches have been posted to their respective bug pages. Please view the project page for further details.