Updates from June, 2010 Toggle Comment Threads | Keyboard Shortcuts

  • danielsaidi 12:29 pm on June 12, 2010 Permalink | Reply
    Tags: equals, , same,   

    Equals vs. same in QUnit 

    When asserting whether or not two associative arrays (or objects) are identical, I first tried to use equals:

       equals({"foo":"bar"}, {"foo":"bar"}, "");

    Turns out, this does not work (see the assertEquals definition). Instead, use same:

       same({"foo":"bar"}, {"foo":"bar"}, "");

    Still, I like the error message you reveice when using equals:

    failed, expected: { “foo”: “bar” } result: { “foo”: “bar” }

     
  • danielsaidi 5:55 pm on June 10, 2010 Permalink | Reply
    Tags: inheritance, , json,   

    jQuery, object inheritance and JSON 

    When developing a hobby project of mine, I previously used both MooTools and jQuery as embedded toolkits. Now, however, I have decided to exclude MooTools and only keep jQuery.

    MooTools have some really nice features, but since i only used its object inheritance and JSON implementation, I decided to exclude it in the upcoming 1.0 release. The less 3rd part components, the better.

    Class inheritance

    When I no longer have the MooTools Object class, I use the jQuery extend function to create inheriting classes, as such:

    function InheritingClass() {
       $.extend(this, new BaseClass("optional parameters"));
    };

    while the MooTools Object class required a syntax like this:

    var InheritingClass = Class({
       Extends: BaseClass,
       initialize: function() { this.parent("optional parameters"); }
    });
    

    The later example requires knowledge about the MooTools object model, while the first only requires that developers know how to use the extend method.

    JSON encoding/decoding

    MooTools features a nice JSON encode/decode implementation, which I will thus not be able to use anymore, so I had to find an alternative.

    jQuery contains (at least) two functions that can be used to handle JSON – parseJSON and serializeArray. However, the later only works with DOM elements, so it is not really what I was after.

    After doing some reading, it seems like the official json.org JSON JavaScript implementation is the best around, while a jQuery plugin that I found had quite an extensive issue list.

    So, although it makes me depend on yet another 3rd part component, I chose this nice little class, which I have used before. MooTools is hereby completely replaced with jQuery (and the small JSON class).

     
  • danielsaidi 9:37 am on June 9, 2010 Permalink | Reply
    Tags: @import, ,   

    / in URL query makes CSS @import and file paths fail 

    I am currently implementing CSS file bundling, which uses a virtual path to a PHP file, as such:

       ~/bundle/bundle.css&cssFolders=... => ~/bundle/bundle.php&type=css&cssFolders=...
    

    Since I provide paths to my CSS folders, a bundle URL may look like this:

       ../bundle/bundle.css&cssFolders=css/,shared/css/

    My bundle file then builds the resulting CSS content by importing all files that it finds, for instance:

       @import url("../css/x.css");
       @import url("../shared/css/y.css");
    

    Thus solution, however, did only work in some cases, while failing for other. I was confused…then I found the solution.

    The / chars in the URL query makes the @import statement fail, since it seems to count all / in the URL, not just all the / in the path excluding the query. This is quite understandable, since .css files are not really meant to handle query variables.

    In this case, however, we have  a virtual .css file that handles query variables, which is why we need to solve this problem.

    The solution, in this case, is to count the number of / in the query variable cssFolders and add an extra ../ for each / in the import statements. I will not show any code examples here, you will find it in the next post.

     
  • danielsaidi 12:19 am on June 9, 2010 Permalink | Reply
    Tags: , , , virtual file   

    Bundle CSS files with relative file paths 

    I am currently working with bundling CSS files, and have to be able to bundle files from many different folders, when needed.

    Previously, all CSS files within the selected CSS folder (if any), as well as within a mandatory system css folder, were added to the virtual bundle file. The theme engine parsed all files and added them to the virtual file output as one mega string:

       .validation-error{border: solid 1px #bb4444;background: #ffdddd;}.RatingBar .images a{display: inline-block; width: 20px;height: 20px;}.RatingBar .unrated { background-image: url(../../../wigbi/content/img/controls/RatingBar/rating_unrated.gif); }.RatingBar .rated { background-image: url(../../../wigbi/content/img/controls/RatingBar/rating_rated.gif); }.RatingBar .half { background-image: url(../../../wigbi/content/img/controls/RatingBar/rating_half.gif); }.RatingBar .createdBy { background-image: url(../../../wigbi/content/img/controls/RatingBar/rating_createdBy.gif); }.RatingBar .hover { background-image: url(../../../wigbi/content/img/controls/RatingBar/rating_createdBy.gif); }@import url(../../../box.css);@import url(../../../classes.css);@import url(../../../controls.css);@import url(../../../design.css);@import url(../../../elements.css);@import url(../../../grid.css);@import url(../../../lists.css);html, body{margin: 0px;background-color: #FFFFFF;background-image: none;}.box{border: solid 1px #bbbbbb;}.box .body{padding: 5px;border: solid 2px white;background: #f6f6f6;}.w100 { width: 100%; }.w95 { width: 95%; }.w90 { width: 90%; }.w85 { width: 85%; }.w80 { width: 80%; }.w75 { width: 75%; }.w70 { width: 70%; }.w65 { width: 65%; }.w60 { width: 60%; }.w55 { width: 55%; }.w50 { width: 50%; }.w45 { width: 45%; }.w40 { width: 40%; }.w35 { width: 35%; }.w30 { width: 30%; }.w25 { width: 25%; }.w20 { width: 20%; }.w15 { width: 15%; }.w10 { width: 10%; }.w5 { width: 5%; }.align-center { text-align: center; }.align-left { text-align: left; }.align-right { text-align: right; }.valign-middle { vertical-align: middle; }.valign-top { vertical-align: top; }.float-left { float: left; }.float-right { float: right; }.bold { font-weight: bold; }.bold-italic { font-weight: bold; font-style: italic; }.italic { font-style: italic; }.invisible { display: none; }.clear { clear: both; }span.large { font-size: 1.3em; }span.yellow { color: #ff9900; }img.border{padding: 3px;border: solid 1px #cccccc;}#main-content-middle img.top{padding-bottom: 15px;}div.separator{margin-top: 10px;margin-bottom: 10px; font-size: 1px;height: 5px;border-bottom: solid 1px #dddddd;background-image: url(../../../img/themes/pro/bg_lines.gif);}#main-content-right div.section-title{height: 25px;padding: 3px;background: #f6f6f6;border-top: solid 1px #cccccc;border-bottom: solid 1px #cccccc;}#main-content-right img.section-icon{float: left;margin-right: 8px;}#main-content-right div.section-text{font-weight: bold;margin-top: 7px;margin-bottom: 15px;}.control input[type="text"],.control input[type="password"]{width: 98%;}.control textarea{width: 99%;}.control-body div{margin-bottom: 10px;}.control-footer{margin-top: 10px;text-align: right;}.NewsletterSubscribeForm .email { margin-bottom: 0px; }.NewsletterSubscribeForm .unsubscribe { text-align: right; }html, body{background: #222222;margin: 0px;margin-top: 50px;margin-bottom: 100px;}#main-top, #main-bottom{color: #c4c4c4;}#main-top{padding-bottom: 50px;background-position: bottom;background-repeat: repeat-x;background-image: url(../../../img/themes/pro/bg_top.jpg);}#main-logo{padding: 0px;padding-left: 150px;padding-top: 30px;background-image: url(../../../img/themes/pro/logo.gif);background-repeat: no-repeat;}.main-width{width: 900px;margin: 0 auto;}#main-content { background: white; }#main-content-left { width: 210px; }#main-content-middle { width: 412px; }#main-content-right { width: 220px; }#main-content-left,#main-content-middle,#main-content-right{padding-left: 10px;padding-right: 10px;}#main-content-left, #main-content-right {border-left: solid 1px #cccccc;border-right: solid 1px #cccccc;}#main-bottom{padding-top: 60px;background-position: top;background-repeat: repeat-x;background-image: url(../../../img/themes/pro/bg_bottom.jpg);}#main-bottom-left, #main-bottom-right{color: white;font-size: 0.82em;}#main-bottom-left{padding-right: 10px;border-right: solid 1px #000000;}#main-bottom-right{padding-left: 10px;border-left: solid 1px #333333;}html, body{color: #333333;font-family: Helvetica, Tahoma, Arial, sans-serif, Verdana, Geneva;font-size: 0.9em;}a{color: #ff9900;font-weight: bold;text-decoration: none;}a:hover { color: #ffbb00; }a, ul a { outline: none; }form{padding: 0px;margin: 0px;}h1{font-size: 1.65em;}h2{font-size: 1.4em;margin-top: 25px;border-bottom: solid 1px #cccccc;}h3{margin-top: 25px;margin-bottom: 10px;}h1, h2, h3 { color: #444444; }h1, h2.first, h3.first { margin-top: 0px; }h1.nospace, h2.nospace, h3.nospace { margin-bottom: 0px; }img, a img{border: none}table{border-collapse: collapse;}table td{padding-right: 5px;vertical-align: top;}.grid {}.grid .row {}.grid .row .cell { float:left; width: 100%; }.grid .row.one .cell { float:none; width: 100%; }.grid .row.two .cell { width:50%; }.grid .row.three .cell { width:33.2%; }.grid .row.four .cell { width:25%; }.grid .row.five .cell { width:20%; }.grid .row.six .cell { width:16.6%; }.grid .row.seven .cell { width:14.2%; }.grid .row.eight .cell { width:12.5%; }.grid .row.nine .cell { width:11.1%; }.grid .row.ten .cell { width:10%; }.grid .row, .grid .row .cell.last { overflow: hidden; }.grid .row .cell.last { float:none; width:auto; }.grid.border .row { border-top: solid 1px black; }.grid.border .row.last { border-bottom: solid 1px black; }.grid.border .row .cell { border: none; border-left: solid 1px black; }.grid.border .row .cell.last, .grid.border .row.one .cell { border-right: solid 1px black; }ul.horizontal,#main-menu ul, #main-bottom ul,#main-content-middle ul.titleMenu,#main-content-middle ul.images{margin: 0px;padding: 0px;list-style: none;}ul.horizontal li,#main-menu ul li, #main-bottom ul li,#main-content-middle ul.titleMenu li,#main-content-middle ul.images li{display:inline;}ul.vertical-list,#main-subMenu ul, #main-content-middle ul{border-top: solid 1px #cccccc;margin: 0px;padding: 0px;list-style: none;}ul.vertical-list li,#main-subMenu ul li, #main-content-middle ul li{border-bottom: solid 1px #cccccc;margin: 0px;padding: 5px;}ul.vertical-list li.even,#main-subMenu ul li.even, #main-content-middle ul li.even{background-color: #f3f3f3;}ul.vertical-list li.selected,#main-content-middle ul li.selected{border-bottom: solid 1px #bbbbbb;background-color: #eaeaea;}ul.vertical-list li.separator,#main-subMenu ul li.separator, #main-content-middle ul li.separator{font-size: 0.1em;background: url(../../../img/themes/pro/bg_lines.gif);}ul.vertical-list li:hover,#main-subMenu ul li:hover, #main-content-middle ul li:hover{background-color: #f9f9f9;}#main-menu li{font-size: 1.5em;font-weight: bold;}#main-menu li { margin-right: 10px; }#main-menu li a { margin-right: 5px; }#main-bottom li { margin-right: 5px; }#main-bottom li a { margin-right: 3px; }#main-menu li a, #main-subMenu li a, #main-bottom li a { text-decoration: none; }#main-menu li a, #main-bottom li a { color: white; }#main-subMenu li a { color: black; }#main-subMenu li a, #main-bottom li a { font-weight: normal; }#main-menu li.selected a, #main-subMenu li.selected a, #main-menu li a:hover, #main-subMenu li a:hover, #main-bottom li a:hover, #main-bottom li.section, #main-bottom li a.more{color: #ff9900; }#main-subMenu li.selected{background-image: url(../../../img/themes/pro/bg_subMenu_selected.gif);background-repeat: no-repeat;}#main-subMenu li.selected a{font-weight: bold;padding-left: 5px;}#main-bottom li.section { width: 90px; }#main-bottom li.section, #main-bottom li a.more { font-weight: bold; }#main-content-middle ul.titleMenu{padding:5px;padding-top:7px;margin:0px;margin-top: 10px;text-align: center;background-color: #f8f8f8;border-bottom: solid 1px #cccccc;}#main-content-middle ul.titleMenu li,#main-content-middle ul.titleMenu li:hover{background: none;padding: 10px;border-bottom: none;}#main-content-middle ul.titleMenu li a{color: #505050;}#main-content-middle ul.titleMenu li a:hover{color: #ff9900;}#main-content-middle ul.images{border: none;text-align: center;}#main-content-middle ul.images li,#main-content-middle ul.images li:hover{padding: 5px;border-bottom: none;}#main-content-middle ul.images img{padding: 3px;border: solid 1px #cccccc;}#main-content-middle ul.images img { margin-bottom: 8px; }#main-content-middle ul.songs, ul.songs{margin-top: 10px;}ul.songs li,ul.songs li:hover{line-height: 23px;padding: 0px;padding-top: 4px;}ul.songs li span { float: right; }#lbOverlay {position: fixed;z-index: 9999;left: 0;top: 0;width: 100%;height: 100%;background-color: #000;cursor: pointer;}#lbCenter, #lbBottomContainer {position: absolute;z-index: 9999;overflow: hidden;background-color: #fff;}.lbLoading {background: #fff url(../../../img/slimbox/loading.gif) no-repeat center;}#lbImage {position: absolute;left: 0;top: 0;border: 10px solid #fff;background-repeat: no-repeat;}#lbPrevLink, #lbNextLink {display: block;position: absolute;top: 0;width: 50%;outline: none;}#lbPrevLink {left: 0;}#lbPrevLink:hover {background: transparent url(../../../img/slimbox/prevlabel.gif) no-repeat 0 15%;}#lbNextLink {right: 0;}#lbNextLink:hover {background: transparent url(../../../img/slimbox/nextlabel.gif) no-repeat 100% 15%;}#lbBottom {font-family: Verdana, Arial, Geneva, Helvetica, sans-serif;font-size: 10px;color: #666;line-height: 1.4em;text-align: left;border: 10px solid #fff;border-top-style: none;}#lbCloseLink {display: block;float: right;width: 66px;height: 22px;background: transparent url(../../../img/slimbox/closelabel.gif) no-repeat center;margin: 5px 0;outline: none;}#lbCaption, #lbNumber {margin-right: 71px;}#lbCaption {font-weight: bold;}

    This is great, right? Nice, clean and compact.

    However, this approach – which can be found in various CSS bundle solutions around the web – suffers from a major flaw…file paths. Since the virtual file most probably does not exist at the same folder level in the file system as the parsed files, all paths in the bundle file will be invalid. This is especially true when parsing files from many different folders.

    The approach above requires you to either use absolute paths in your css files or have the css files at the same folder level in the file system as the bundle file. This is not always applicable, especially since I want to allow developers to point out any folder as css folder.

    It is possible, though, by providing the bundle file with various file system information, to acount for the path differences and change the file paths so that they work within the bundle file. This, however, involves way too much work and testing for me to be interested in implementing such a solution…at least now.

    So, I have now taken a step back. The bundle file still remains, but instead of adding all file content to the output as above, I simply import all files of interest into it. The virtual file output will thus look something like this:

       @import url("../css/default.css");@import url("../../wigbi/css2/x.css");@import url("../../wigbi/css2/y.css");

    This is not as fast as the compact first option, since I have no possibility of compressing the CSS code. However, but by linking to the CSS files like this, I do not have to account for file paths within each file. It works automatically…like a charm 🙂

     
  • danielsaidi 6:45 pm on June 3, 2010 Permalink | Reply
    Tags: , , , ,   

    Hide successful QUnit tests 

    I am now rolling with QUnit as TDD framework for my JavaScript development. It’s not as sophisticated as say NUnit for .NET or SimpleTest for PHP, but it’s reaaally easy to get started with.

    However, a strange way of designing the test result presentation is that QUnit lists all tests, not just the ones that fails. With just a few executing tests, the resulting page looks like this:

    QUnit - Full test result presentation

    By default, QUnit lists all executing tests in a test suite

    The test suite above only includes 14 tests – imagine having maybe a hundred or so! In my opinion, this way of presenting the test result hides the essence of testing – to discover tests that fail.

    I understand that one must be able to confirm that all tests are executed, but the number of executed tests are listed in the result footer. So, I would prefer to only list the tests that fail.

    If anyone knows a built-in way of achieving this, please let me know. I chose the following approach (applies to jQuery 1.4.2 – let me know if this is out-of date):

    1. Open the qunit.js file
    2. Find the block that begins with the line:
      var li = document.createElement("li");
    3. Wrap the entire block within:
      if (bad) { ... }

    This will make QUnit only append the list element if the test is “bad”, that is if it failed. The result will look like this:

    After fiddling with the code, QUnit only lists failing tests

    Maybe there is a built-in way of making QUnit behave like this. If you know how, please leave a comment.

     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel