Archive for category Mercurial Project

v1.0 Release Complete

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:

Finally, the release is done! All the patches have been posted to their respective bug pages. Please view the project page for more information.

, , ,

No Comments

v1.0 Release - Various Changes to Improve the OnScroll Patch

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 &lt; vHeight) {
    for(var count = 0, offSetHeight = document.body.offsetHeight; offSetHeight &lt; vHeight; count++)
      offSetHeight += 180;
 
    if(count &gt; 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.

,

No Comments

v1.0 Release - Changing the Data Structure that Handles Merges for the OnScroll Patch

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.

, ,

No Comments

v1.0 Release - Further Improving Bug Functionality for the OnScroll Patch

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.

, ,

1 Comment

v1.0 Release - Getting the Localize Dates Link Working with the New Entries Loaded On Scroll

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!

, ,

1 Comment

v1.0 Release - Fixing the OnScroll Patch to Work with the New Version of hg_templates

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.

, ,

No Comments

v1.0 Release - Expand/Collapse Functionality only for Merges with >5 Pushes

In my goals post I outlined that I wanted to take on a new bug. This bug outlines that only merges that have >5 pushes should be given expand/collapse functionality. Any merge that contains <5 pushes should be shown normally. I guess, when the original expand/collapse bug was fixed we all forgot about this little feature. No big deal though because I’m gonna fix it now.

The following is the current server-side code:

396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
if id != lastid:
  lastid = id
  p = parity.next()
  entry["push"] = [{"user": user,
                  "date": localdate(date)}]
  if len([c for c in ctx.parents() if c.node() != nullid]) > 1:
    mergehidden = "hidden"
    entry["mergerollup"] = [{"count": 0}]
  else:
    mergehidden = ""
  currentpush = entry
else:
  entry["hidden"] = mergehidden
  if mergehidden:
    currentpush["mergerollup"][0]["count"] += 1
entry["parity"] = p
l.append(entry)

This is where the change will have to be made. Lets have a look here. On line 401 there’s an if statement that executes to true if the changeset has more than one parent, which means that it is a merge changeset. Then, the following lines setup the expand/collapse functionality. It is line 401 where I will make the change to implement this functionality.

A merge changset should have 2 parents. So, in order to find out how many pushes there are in the merge I just do a simple substraction between the rev number of parent 0 and the rev number of parent 1. The result will tell me how many pushes that merge contains. Only implement expand/collapse functionality for the merge if the result is greater than 5.

The new code:

396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
if id != lastid:
  lastid = id
  p = parity.next()
  entry["push"] = [{"user": user,
                  "date": localdate(date)}]
  if len([c for c in ctx.parents() if c.node() != nullid]) > 1 and ctx.parents()[0].rev() - ctx.parents()[1].rev() > 5:
    mergehidden = "hidden"
    entry["mergerollup"] = [{"count": 0}]
  else:
    mergehidden = ""
  currentpush = entry
else:
  entry["hidden"] = mergehidden
  if mergehidden:
    currentpush["mergerollup"][0]["count"] += 1
entry["parity"] = p
l.append(entry)

As you can see above I only needed to change line 401 to implement this change. It’s always great to be able to add new functionality without needing additional lines of code. A win win!

,

No Comments

v1.0 Release - Expand/Collapse for the Files Touched Patch

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# &mdash; #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.

,

No Comments

v1.0 Release Goals

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.

,

No Comments

v0.9 Release Complete

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:

The patches have been posted to their respective bug pages. Please view the project page for further details.

, , ,

No Comments