TestSwarm for Popcorn on iOS

Today, David Seifried and I worked on getting TestSwarm to run the Popcorn unit tests on the iOS simulator. Previously, the simulator kept saying that there were no jobs to run. After some digging and trying different things out, Dave figured out what the problem was. The simulator is now able to run the tests when a job is pushed up to it! This is very good.

The reason we need to create our own custom app is because Safari requires user action in order for media playback to occur. This doesn’t work for the purposes of automated testing. When first thinking about this problem, I initially thought that I was going to need to inject JavaScript into the WebView that would eventually lead to the Objective-C triggering the video to play. But, the fix for this actually ended up being simple, and I found it when I wrote an older post, DPS911 Release 3. As stated in that post, the UIWebView class has a mediaPlaybackRequiresUserAction property that I can set to no, which will let videos play automatically.

The code for that is:

[[self theWebView] setMediaPlaybackRequiresUserAction:NO];

And it works! Just one line. Now TestSwarm can run Popcorn tests on iOS using the simulator and the physical device!

Posted in Open Source | Leave a comment

Butter: Bug 459

In my post, Butter: Bugs 256 and 290, I said that there was a problem with one of the tickets that I reviewed, and that bug 459 was filed to deal with it. This bug involves fixing the error message given to the user. Although this is simple, I find it very important to display meaningful, consistent messages to the user. It adds to the user experience.

Before, when an invalid start or end time for a track event was entered, the error message displayed was:

You’ve entered an invalid start or end time. Please verify that they are both greater than 0, the end time is equal to or less than the media’s duration, and that the start time is less than the end time.

I have changed it to

You have entered an invalid in or out time. Please verify that

  • Both in and out times are greater than 0.
  • The out time is equal to, or less than the media’s duration (duration of the media, in seconds, displayed here).
  • The in time is less than the out time.

Three things to note are:

  • The error message now refers to start and end times as in and out times, since that is how it is displayed to the user in the editor.
  • The media’s duration is displayed in the error message.
  • The error message is now displayed as a bulleted list for readability.

The pull request for this patch is here.

Posted in Open Source | Leave a comment

Butter: Bug 434 Status

For the past couple of days, I have been working on bug 434 in Butter, which is to allow users to move multiple track events at the same time. This is definitely not as straightforward as it seems.

Initially, I was thinking that since the dragging behaviour already exists in the track event, I could just have a loop that goes through all of the selected track events, and trigger the dragging behaviour on each one. After trying various things in the code, I realized that making this trigger happen wasn’t obvious.

I started doing some searches, and ended up reading this post on StackOverflow. I implemented something similar to the selected answer, which is to implement the helper function in jQuery’s draggable to return all of the elements to be dragged appended to one container. The suggestion in the post was this:

$('#dragSource li').draggable({
  helper: function(){
    var selected = $('#dragSource input:checked').parents('li');
    if (selected.length === 0) {
      selected = $(this);
    }
    var container = $('
').attr('id', 'draggingContainer'); container.append(selected.clone()); return container; } });

This person also put up a demo on JSBin, and it seemed like this is exactly what I wanted. But, after trying it in Butter, it ended up having unsuitable behaviour. Everything that was appended to the div appeared on top of each other, and that means that the track events were losing their place when they were being dragged. I could have done some styling with the container div so that the track events would keep their position, but this seemed like a hack that wouldn’t work.

Moving on, I found this post on the jQuery UI Google Group, which says to capture the mousedown event on the container, and then from there trigger the even on the draggables, which should start the dragging operations on all of the events. The code for that looks like this:

$(".draggable").draggable();

$("#container").mousedown(function(e) {
    $(".draggable").trigger(e);
});
​

This works for the first draggable element in the HTML, but not for the rest. There is also an error thrown in the console (I deleted much of error here because it’s too long):

jQuery.event.dispatch
jQuery.event.add.elemData.handle.eventHandle
jQuery.event.trigger
jQuery.fn.extend.trigger
jQuery.extend.each
jQuery.fn.jQuery.each
jQuery.fn.extend.trigger
(anonymous function)
jQuery.event.dispatch
jQuery.event.add.elemData.handle.eventHandle
jQuery.event.trigger
jQuery.fn.extend.trigger
jQuery.extend.eachjquery-1.7.1.js:658

.....

jQuery.event.trigger
jQuery.fn.extend.trigger
jQuery.extend.each
jQuery.fn.jQuery.each
jQuery.fn.extend.trigger
(anonymous function)

Changing the code up a bit would just give me another error, saying that there is too much recursion. So I tried to do this:

$(".draggable").draggable();

$("#container").mousedown(function(e) {
    $(".draggable").trigger(e);
});

$(".draggable").mousedown(function(e) {
    e.stopPropagation();
});

This does not throw an error, but again there is the issue that the dragging operation only works on the first draggable in the HTML.

Similarly, I found this bug filed in jQuery three years ago. It suggested writing the code like this:

$('#draggable').one('mousedown', function(e) {
    $("#draggable").draggable().trigger(e);
});

This didn’t work either, since the mousedown event was only captured once.

I then found another discussion on the jQuery forum, where rdworth mentions that jQuery uses the simulate plugin, and linked to examples of how it’s used in the jQuery unit tests. This looked like it was a bit overboard for what we’re trying to do, so I needed to find something else.

I was trying to stay away from introducing another external plugin to Butter, but it seems that I need to. I found this multidraggable jQuery UI plugin. I tried it out, and it works, but the one problem is that it doesn’t let the developer choose which elements are to be dragged. The way the elements are selected to be dragged is done within the plugin itself, using a control-click. This is an issue because Butter has it’s own way of deciding which track events are selected.

Finally, I found another plugin by ThreeDubMedia, which provides both drag and drop plugins. These plugins are set up to give the developer a lot of control, which is good for our case. I now have some code that moves multiple track events, but now that the jQuery UI draggable plugin is not being used, other areas need to be rewritten. For example, the scrolling feature that’s available automatically with the jQuery UI draggable plugin doesn’t seem to exist in the plugin provided by ThreeDubMedia, which means code for that has to be created.

So far, this is what I have:

function drag ( ev, dd ) {
    $( this ).css({
        top: dd.offsetY,
        left: dd.offsetX
    });
}

$( _element ).css({
    zIndex: 9001
});
$( _element ).drag( "init", function() {
    return $( "div[selected=true]" );
}).drag( "end", movedCallback ).drag(drag, {
    relative: true
}).resizable({ 
    autoHide: false, 
    containment: "parent", 
    handles: "e, w", 
    scroll: false,
    stop: movedCallback
});

Oh, and I also found an accidental global variable, _selectedEvents, in src/timeline/media.js. I will also fix that in the patch I submit.

Posted in Open Source | Leave a comment

Butter: Bugs 256 and 390

Butter 0.2 has been released. Bobby Richter, and David Seifried have written in detail what it’s about.

Leading up to the release, I fixed up the bugs listed in my DPS911 Release 3 blog post, namely, bug 256, and 390.

I spent time fixing up the bugs, and I sent up the changes to GitHub. Bobby, however, knowing I was working on writing a paper, kindly decided to combine the solution of bug 256 and 390 into one, and he sent up his solution in this pull request. Seeing as I was the one working on those tickets and already knew the code, and that I had a solution up already, I did the peer review (well, actually, it was assigned to David Seifried, I just started adding comments on GitHub, and that’s when Dave assigned it to me). From the comments I made, some were accepted, some rejected, and a ticket was created for a couple of others. It’s always nice to have a mix.

One of the changes involved an error message that was given. After entering in an invalid start and end time for a track event, the message given is: “You’ve entered an invalid start or end time. Please verify that they are both greater than 0 and less than the duration of the media”. The two issues with this are:

  • The end time can be equal to the duration of the video.
  • The duration of the video isn’t shown anywhere.

The message was then changed to say: “You’ve entered an invalid start or end time. Please verify that they are both greater than 0, the end time is equal to or less than the media’s duration, and that the start time is less than the end time.” This fixed the first issue; a bug was filed to deal with second: Bug 459 was created to add in the duration to the error message.

The solution in the pull request above includes validating the start and end times of a track event. The patch, however, does this validation in the track event editor. The problem with this is that if another editor is made down the the road, or if a track event is edited somewhere else in the code, this validation is by-passed, and the bug will show up again. Because Butter was to be released that night, the current solution made it in, but another bug was filed to deal with this issue specifically, bug 458. There were other minor fixes as well, all in the pull request linked above. The ones listed here are the more important ones.

It is really interesting seeing the changes being made in Butter, it is is starting to look really good. I am loving the highlighting feature that allows users to visually see which part of the web page the plugin they are using will affect. Right now, I am working on two bugs. The first is bug 434, which is to allow moving multiple track events at the same time. The second one is bug 459, linked earlier, which is to add the duration of the video to the error message given when an invalid start or end time for a track event is entered.

Posted in Open Source | Leave a comment

DPS911 Release 3

This release I worked on Butter and TestSwarm for iOS.

Bug 256: Round timecodes

I had this in review before, and since then it has gone through a series of changes. Even after it was staged. My earlier post on this bug showed that I created a function, round, that would round a number given to it (round is underscored, because that’s how private variable are denoted now in Butter). The code now looks like this:

_round = function( number, numberOfDecimalPlaces ) {
  return Math.round( number * ( Math.pow( 10, numberOfDecimalPlaces ) ) ) / Math.pow( 10, numberOfDecimalPlaces );
};

In order to use the function, every place that calls the _round function has to pass in a number, and I kept passing in 3 every time. As Bobby suggested, this should be made into a const. So at the top of the file, I declared it as

const NUMBER_OF_DECIMAL_PLACES = 3;

because I saw it done that way in several other places in the code. But Jon Buckley noted that const is only supported on Firefox and Chrome, and linked to this page. So I changed the const to var, and also created another ticket to change all consts in Butter to vars.

After this was staged, Matthew Schranz found that when moving a track event by dragging and dropping, the 3 decimals were not being properly shown. This issue came up because the rounding function doesn’t add 0s to the end of a number. For example, a number like 12.44 will remain as 12.44, and will not become 12.440. We also decided to make the round function available to other places in the code. I ended up adding the function as a static function on Butter, and also made numberOfDecimalPlaces a static member on Butter, instead of an argument to the round function. This way the number of decimal places can be set in the code.

To fix the rounding issue Matthew was seeing, in the default editor, I added this code:

if ( item === "start" || item === "end" ) {
  newItem.value = popcornOptions[ item ].toFixed( 3 );
}
else {
  newItem.value = popcornOptions[ item ];
}

Taking advantage of the fact that the start and end times in the text fields are presented as strings, and that the toFixed returns a string, I used the toFixed function on the start and end times. That way, a start time of 0 will show up as 0.000, and a start time of 1.2 will show up as 1.200, giving a consistent view to users. I submitted another pull request, and Bobby gave me some review. I now have to

  • change numberOfDecimalPlaces to timeAccuracy
  • move the round function into util/time, instead of a static function on Butter

Bug 410: Change consts to vars

As noted earlier, I created another ticket to change all occurrences of const to var. This has already been staged, and the pull request for that (as well as the diff) is here.

Bug 390: Validate start and end times

Currently, a user can enter in a start or end time for a track event that is longer than the duration of the video. Since this doesn’t make sense, we need to show the user a message when it happens. One possible solution is to do the validation in the track event editor, but this only masks the problems. If another editor is created down the line, or if a track event is edited somewhere else in the code, then this bug will show up again. I decided to add this validation in the update function in the src/core/trackevent.js file. This way, no matter where the code is being updated from, the start and end times will be validated.

The update function now looks like this:

this.update = function( updateOptions ) {
  var errorMessage;
  if ( updateOptions.start >= _round( butter.duration, NUMBER_OF_DECIMAL_PLACES ) ) {
	errorMessage = "The in time cannot be greater than or equal to the duration of the video, which is " + _round( butter.duration, NUMBER_OF_DECIMAL_PLACES ) + " seconds.";
	_em.dispatch( "trackeventupdatefailed", errorMessage );
	return;
  } //if
  if ( updateOptions.end > _round( butter.duration, NUMBER_OF_DECIMAL_PLACES ) ) {
	errorMessage = "The out time cannot be greater than the duration of the video, which is " + _round( butter.duration, NUMBER_OF_DECIMAL_PLACES ) + " seconds.";
	_em.dispatch( "trackeventupdatefailed", errorMessage );
	return;
  } //if

  for ( var prop in updateOptions ) {
	if ( updateOptions.hasOwnProperty( prop ) ) {
	  _popcornOptions[ prop ] = updateOptions[ prop ];
	} //if
  } //for
  if ( _popcornOptions.start ) {
	_popcornOptions.start = _round( _popcornOptions.start, NUMBER_OF_DECIMAL_PLACES );
  }
  if ( _popcornOptions.end ) {
	_popcornOptions.end = _round( _popcornOptions.end, NUMBER_OF_DECIMAL_PLACES );
  }
  _em.dispatch( "trackeventupdated", _this );
}; //update

This function now checks for the errors at the top of the function. If it finds out, it sends out a trackeventupdatefailed failed event with a message, and returns early. Returning early here means the code that updates and sends the trackeventupdated event will not run, meaning that all of the code that listens and reacts to the trackeventupdated event will not run.

In order for this to work, some code has to be added to src/editor/editor.js so that it can send the trackeventupdatefailed event to the track event editor. In this file, once a trackeventupdatefailed is received, it runs this code:

butter.dialog.send( _dialogName, "trackeventupdatefailed", e.data );

Finally, the editor listens for trackeventupdatefailed, and simply displays the message to the user:

_comm.listen( "trackeventupdatefailed", function( e ) {
  document.getElementById( "message" ).innerHTML = e.data;
});

This is good because now when a new check is added for the track event in src/core/trackevent.js the error messages will automatically be shown if necessary in the editor. Bobby liked this approach, and wants the solution to either line up or replace another bug, bug 313, which is to make sure that the start and end times are actually valid numbers. The pull request and diff for this commit is here. I have feedback on it, which says

  • the butter variable is only global for debugging
  • store the rounded value of the video’s duration into a variable, instead of calculating it every time

TestSwarm for Popcorn

As stated in my blog post DPS911 Release 1, “we need a way to let the videos needed for Popcorn’s test cases to play automatically, without someone having to sit there and hit the play button”.

David Seifried fixed the issue of the web page not providing content to the iPhone device and simulator. The issue now is that tests run on a phsyical device, but on the simulator it simply says that there are no jobs left in the queue. This is going to require investigating. As I was writing this section of the blog, I think I found the solution to the problem of videos not playing unless a user clicks play. The UIWebView class has a mediaPlaybackRequiresUserAction variable that I can set to no, which will let videos play automatically! I will test that out as soon as we can get the simulator to start running tests.

Posted in Open Source | Leave a comment

DPS911 Release 2

Release 2

This is my second release for David Humphrey’s open source class. I spent the majority of my time this release working on getting ChocTop to work in Popcorn Maker FCP, so that when users open Popcorn Maker FCP’s DMG file to install the application, they are presented with custom images. This post goes into detail, and also explains the issues I ran into along the way. I am happy that I was finally able to get ChocTop to work; I was working with tools that I haven’t used before, and running into errors I’ve never seen or dealt with before either. Having these tools not throw run-time errors every time I want to use them is a good feeling. Now that I have it working, the next iteration will involve talking to people on IRC in order to make it look the way we want.

I also worked on three Popcorn Maker bugs, which are now up for review, as explained in this post. I am still working on bug 254 for Popcorn Maker, which is to remove the apply button from anywhere in the application in order to eliminate the confusion between the differences of the apply and okay button.

Reflecting on Release 1 Goals

Reflecting on what I needed to work on from my first release:

  • This release I did blog and tweet about my process as I was doing it
  • I used IRC more as well, but I can still be more active on it
  • I was on Twitter much more, getting more involved with the community

Next Release

I am looking forward to working on getting TestSwarm to work on iOS with David Seifried next week, as well as polishing up the DMG file for Popcorn Maker FCP, and working on more Popcorn Maker bugs.

Posted in Open Source | Leave a comment

Popcorn Maker Bugs 256, 257, and 281

Three bugs that I now have up for review are:

  • bug 256 – Timecodes should round to three decimal places
  • bug 257 – Remove .DS_Store files from the repository
  • bug 281 – Fix the basic template’s manifest file

Bug 256 – Timecodes Should Round to Three Decimal Places

There were a couple of places that looked like could be the right area to modify the code, namely butter/external/trackLiner/trackLiner.js, and butter/src/core/trackevent.js. trackLiner.js is what responds first when a track event is added to the timeline. I tried looking for the right area in the code to change, but then realized in order to keep trackLiner.js more flexible for other components that want to use it (perhaps they want more precision), the rounding should be done in trackevent.js. The initial comment for this bug said that timecodes should be rounded to one decimal place, and that’s what my first patch had. But I got comments in the ticket saying it would make more sense to have it round to three decimal places in order for people to have frame-level precision. I also ended up using JavaScript’s toFixed function to do the rounding, but I had to change that since it was pointed out to me that the function returns a string. In my second implementation, I created a local function, round, which uses a little bit of math to do the rounding. The function is

round = function( number, numberOfDecimalPlaces ) {
  return Math.round( number * ( Math.pow( 10, numberOfDecimalPlaces ) ) ) / Math.pow( 10, numberOfDecimalPlaces );
};

Each place in the code that calls it passes 3 to the second argument of the function, so that the number returned is rounded and has only three decimal places. The patch for this bug is here.

Bug 257 – Remove .DS_Store Files from the Repository

This one didn’t involve any code, it was solved using the find command:

find . -name .DS_Store -exec git rm {} \;

That command executes git rm on each file in the repository named .DS_Store.

Bug 281 – Fix the Basic Template’s Manifest File

The manifest file for the basic template had two description fields, so I just removed one of them, and kept the one that says the description is “A simple template with two text areas”. The manifest also said that the thumbnail was named thumbnail.gif, but it needed to be thumbnail.png.

Still Working on Bug 254

I am still working on bug 254, which is to remove the apply button from Popcorn Maker (it’s confusing for users to have both an apply and okay button); I hope for that to be up in review soon!

Posted in Open Source | Leave a comment