Making linking between anchors in an IFrame work in Chrome and Firefox 11+

About a year ago I wrote the post Making linking between anchors in an IFrame work in Firefox 4 and above which detailed a workaround for making anchor tags in IFrame’s function as expected. Unfortunately this fix stopped working as of Firefox 11 and in Chrome as well.  Firefox changed how it calculated the offset of an element inside of the IFrame. It used to calculate it relative to the parent window but now calculates relative to the IFrame window. To fix this you now must add the distance between the top of the page and the IFrame in the call to the scrollto function.

Here is the updated code:

$(function() {
  var iframeOffset = $("#ID_OF_MY_IFRAME", window.parent.document).offset();
  $("a").each(function () {
      var link = $(this);
      var href = link.attr("href");
      if (href && href[0] == "#") {
          var name = href.substring(1);
          $(this).click(function () {
              var nameElement = $("[name='" + name + "']");
              var idElement = $("#" + name);
              var element = null;
              if (nameElement.length > 0) {
                  element = nameElement;
              } else if (idElement.length > 0) {
                  element = idElement;
              }

              if (element) {
                  var offset = element.offset();
                  window.parent.scrollTo(offset.left, offset.top + iframeOffset.top);
              }

              return false;
          });
      }
  });
});

 

When using this code you must update the text “#ID_OF_MY_IFRAME” with the id that you give the IFrame tag in the parent page.

I create a demo page where you can see the above fix in action.

 

Making linking between anchors in an IFrame work in Firefox 4 and above

Update: For Firefox versions 11 and up see the update code.

In Firefox 4 a security fix was added which prevents linking between anchors within an IFrame that does not have scroll bars. This change breaks the scenario where you have an IFrame that has a “Go To Top” link (<a href=”top”>Go to top</a>) which links to an anchor tag (<a name=”#top” />) at the top of the IFrame.  If this IFrame does not have scroll bars then clicking the link will scroll the parent page to bring the anchor into view. This can be a security issue which is why Firefox is the first browser to block it.  However, I believe they should have added an exception for the case when the IFrame and the containing page satisfy the Same Origin Policy.

I worked around this limitation by adding the following code to my IFrame (my implementation uses jQuery) which will override the anchor link functionality and scroll the window programmatically. This code makes use of the window.parent property which means it is subject to the Same Origin Policy.

$(function(){
  $("a").each(function (){
    var link = $(this);
    var href = link.attr("href");
    if(href && href[0] == "#")
    {
      var name = href.substring(1);
      $(this).click(function() {
        var nameElement = $("[name='"+name+"']");
        var idElement = $("#"+name);
        var element = null;
        if(nameElement.length > 0) {
          element = nameElement;
        } else if(idElement.length > 0) {
          element = idElement;
        }

        if(element) {
          var offset = element.offset();
          window.parent.scrollTo(offset.left, offset.top);
        }

        return false;
      });
    }
  });
});

 

 

Chutzpah – A JavaScript Test Runner Released

I just released to CodePlex and the Visual Studio Gallery a new project called Chutzpah (hutz·pah). Chutzpah is an open source JavaScript unit test runner which helps you integrate JavaScript unit testing into your website. It enables you to run JavaScript unit tests from the command line and from inside of Visual Studio. It also supports running in the TeamCity continuous integration server.

Backstory

About nine months ago I asked a question on StackOverflow about whether there were any tools/extensions which integrated into Visual Studio to run JavaScript unit tests. At that time there were no good solutions provided which led me to investigate creating my own tool. I explored many options but eventually I found the PhantomJS headless browser to help drive the tests.  After a couple weeks of development Chutzpah was born.

What does Chutzpah do?

Chutzpah is both a Visual Studio extension and a command line utility.

As a Visual Studio extension:

It allows you to run your JavaScript tests without leaving the IDE. It adds a context menu option to run tests directly from a source file.

RightMenu

It logs test results to both the Error list and the Output window.

errorWindow

outputWindow

As a command line utility:

It allows you to easily integrate test results into your build

commandLine

It also has support for the TeamCity continuous integration server so that you get detailed test output on every build.

How to use it?

Chutzpah is really easy to use, given QUnit tests (it only supports QUnit for now) you can run Chutzpah on the test harness HTML file and it will output the results. Chutzpah also supports running the tests directly from the JavaScript file as long as you add reference comments to the top of your test file.

For example given two files test.js (QUnit tests file) and code.js (implementation file).

code.js

var mathLib = {
    add5: function (a) {
        return a + 5;
    }
}

test.js

/// <reference path="code.js" />

test("will add 5 to number", function () {
    var res = mathLib.add5(10)

    equals(res, 15, "should add 5");
});

You can run the tests by right clicking and choosing “Run JS Test” if you are using the Visual Studio plugin, otherwise you can execute Chutzpah from the command line:

.\chutzpah.console.exe test.js

Community Support

I am really excited about releasing Chutzpah as an open source project with the hope of garnering support from the community. I would love to get feedback, bug reports, feature requests and code contributions. If you are interested in working on Chutzpah fork the code and get hacking.

Future Plans Ideas

At this stage I have many ideas of what features should come next for Chutzpah but outside of bug fixes I have no solid plans yet. Here are several ideas floating around in my head…

  1. Support other JavaScript unit test frameworks besides QUnit
  2. Expand past only using PhantomJS as the headless browser, possibly working with things like JsTestDriver or EnvJS.
  3. Be able to run individual tests instead of just a whole file.
  4. Add better IDE support like the Resharper 6 QUnit functionality.
  5. Add scanning for test files within a whole project hierarchy
  6. Support proxy servers
  7. Capture more detailed information from each test
  8. Integrate with existing test runners like MSTest or TestDriven.NET
  9. Add NuGet support
 

Visually view all events attached to DOM elements

I recently found this tool called Visual Event which helps you view and inspect all events attached to DOM elements on a web page.  I have wanted a tool like this for a long time.  Often when programming with many events on a page it is hard to see exactly what code is attached to what element.  This tool is able to show you all events attached on a page and allows you to view the code that will execute for that event.

visualEvent1

Visual Event also understands events registered from several different frameworks/methods:

  • DOM 0 events
  • jQuery 1.2.x +
  • YUI 2.6.x (2.x might work!)
  • MooTools 1.2.x
  • Prototype 1.6.x
  • JAK (Events 2.2)
  • Glow

When I tested Visual Event I found that it works great in Opera 11, Firefox 3.6 and Chrome 10 but as listed on their webpage it does not yet support IE at all. It would be really cool if the developer tools in browsers natively supported this functionality but until then I recommend trying this out.

 

A simple JavaScript stubbing function

Stop!

If you are looking for a full featured JavaScript stubbing/mocking library you will be thoroughly disappointed by this post. There are many really good and full featured frameworks for this such as QMock , JSMock and my current personal favorite Sinon.JS.  However, if you want to see a super simple and useful JavaScript stubbing function in less than 20 lines of code you are in luck.  This function (aptly called stub) does all you need to stub out methods on an object.  You can see how many times a method was called and what is was called with.

Here’s the code:

function stub() {
    return {
        of : function (name, callback, returnValue) {
            this[name] = function () {
              var args = Array.prototype.slice.call(arguments);
              this[name].calls.push(args);
              var ret = null;
              if(callback)
                  ret = callback.apply(this, args);
              if(returnValue) return returnValue;
              return ret;
          };
          this[name].calls = [];

          return this;
        }
    };
}

 

Example

To show how to use this stubbing function take a look at the following function and test case which show some code which uses the HTML Canvas context object to draw and translate a blue sqaure.

Test:

test("will render blue square and translate right 50px", function() {
   var context = stub().of("fillRect")
                       .of("translate");

   renderBlueSquareAndTranslate(10,10, context);

   equal(context.fillRect.calls.length, 1);
   equal(context.translate.calls[0][0], 50);
   equal(context.translate.calls[0][1], 0);
   equal(context.fillStyle, "#0000FF");
});

Implementation:

function renderBlueSquareAndTranslate(height,width, context) {
    context.fillStyle = "#0000FF";
    context.translate(50,0);
    context.fillRect(0,0,height,width);
}

 

Tests

Below are the unit tests I wrote for the stubbing function:

  • Stub a method called “action”, assert that it was called twice and assert that the right values were passed to it in each call.
test("will capture call arguments for multiple calls", function() {
   var s = stub().of("action");

   s.action("matt",8);
   s.action("mal",4);

   equal(s.action.calls.length,2);
   equal(s.action.calls[0][0],"matt");
   equal(s.action.calls[0][1],8);
   equal(s.action.calls[1][0],"mal");
   equal(s.action.calls[1][1],4);
});

  • Stub a method called “action”,  assert callback is invoked when “action” is called and use the callback’s return value as “action”’s return value.
test("will invoke callback with arguments", function() {
   var arg0, arg1;
   var callback = function() { arg0 = arguments[0]; arg1 = arguments[1]; return 10;};
   var s = stub().of("action", callback);

   var res = s.action("matt", 8);

   equal(arg0,"matt");
   equal(arg1,8);
   equal(res,10);
});

  • Stub a method called “action” and use given return value as “action”’s return when no callback is specified.
test("will use returnVal over return value of callback", function() {
   var arg0, arg1;
   var callback = function() { arg0 = arguments[0]; arg1 = arguments[1]; return 5;};
   var s = stub().of("action", callback, 10);

   var res = s.action("matt", 8);

   equal(res,10);
});

  • Stub a method called “action” and a method called “other” and assert only “action” is called.
test("will stub multiple methods and test only one is called", function() {
   var s = stub().of("action").of("other");

   s.action();

   equal(s.action.calls.length,1);
   equal(s.other.calls.length,0);
});