PicNet Custom Software Development

.Net and Javascript Development

Lean css in javascript

Posted on clock April 19, 2010 08:00 by author guido

This weekend I was looking at the lesscss.org project and found it very interesting.  There is also a .net implementation.  The basic features of these projects is to make css less verbose, they do this by offering features like mixins, variables and nested rules.  Now all of this is very straight forward lexical analysis to produce raw css so I thought to myself why does this need a server side component, what if I want to have a pure html site.  I don't want php, ruby, .net, etc just to compile some css.  I also don't want an additional deployment process to compile my css.  So... Why not javascript.

I thought there must be some limitations but a very quick test shows that it is entirely possible.  So here we go:

We want to prevent the bowser from doing 2 requests to css so change all your:


<link rel='stylesheet' href='style.css'/>

With:


<link rel='lss' href='style.css'/> <!-- I have called it lss for less but it can be anything -->

This will prevent the borwser from requesting this file, which is good as we will be manually requesting them. So now lets add a script file to load and parse our lss files:


<script src="jsless.js" type="text/javascript"></script> 

Content of jsless.js (Note I'm using jQuery)

 

$('link').each(function() {

  var lss = $(this);

  var lssurl = lss.attr('href');

  // Should we make this block?  Probably, but lets leave for now

  $.ajax({url: lssurl, dataType:"text", success: function(css) { getcsscallback(lss, css); }});

});

 

function getcsscallback(lss, cssText) { 

  var vars = getVariables(cssText); 

  for (var i in vars) {

  i = trim(i);

  var val = trim(vars[i]); 

  cssText = cssText.replace(/@[A-z^:]+:.*/g, ''); // remove var line

  cssText = cssText.replace(new RegExp(i,  'g'), val); // replace replace variables

  }

  cssText = '<style>' + cssText + '</style>'; // TODO: Add media, etc, etc from the attributes of lss into this tag

  $('head').append(cssText);

}

 

function getVariables(cssText) {

  return getMatches(/(@[A-z^:]+):([^;]+);/g, cssText);

}

/// Following code is just supporting regex and string manipulation code

function getMatches(regex, text) { 

  var matches = {};

  var match = null;

  while (match = regex.exec(text)) {  

  matches[match[1]] = match[2]; 

  }

  return matches;

}

 

function trim(str, chars) {

  return ltrim(rtrim(str, chars), chars);

}

 

function ltrim(str, chars) {

  chars = chars || "\\s";

  return str.replace(new RegExp("^[" + chars + "]+", "g"), "");

}

 

function rtrim(str, chars) {

  chars = chars || "\\s";

  return str.replace(new RegExp("[" + chars + "]+$", "g"), "");

}

 

Thats it, I have a test project set up that you can use to see this in action.  You can also just click here to see the html.  The css (lss) used is here and the js is here.

 

I personally think this project has some potential so if you are interested in working with me just email me and we can set up an OS project and start from there.

 

Note, I have tested the above in chrome, firefox and IE8 and it appears to work.

 

Anyways hopefully this inspires someone to do this properly.

 

Thanks

Guido Tapia

Software Development Manager

PicNet Pty Ltd


Javascript Tips, Tricks and Hacks

Posted on clock April 14, 2010 06:08 by author guido

JavaScript is by far the most expressive language I use today, that expresiveness is a result of the amount of flexibility that the language gives the developer.  This is also the same reason why it is so hard to develop in JS, however I will not be focusing on that here.  This article is solely about the art of JS development.  I will be following this article up with a series of usefull patterns in javascript and usefull utility classes, but for now lets focus on the sugar.

Note: This article is extremely subjective so if any of the following views offend please accept this as my sincerest of apologies.

Variables

Sometimes the way you do things has no impact on the results but it just 'feels' (or 'smells' if you want to Fowler it up) better.  One very clear example is variable declaration.  Example;

var i;

var x = 10;

var y =100;

var product = x*y;

I prefer this:

var i,

     x = 10, 

     y = 100.

     product = x*y;

Why? Don't know, I just do.

Also, you must always remember that assignment always returns the value of the assignment so why not do something like:

var product;

callFunction(product = x * y);

return product;

When doing multy variable assignment (separated by ,) then the last assignment is returned.  This is rarely usefull so no sugar there.

 

Conditions

Become familiar with falsy expressions.  Use them in your conditions.

So instead of:

if (typeof console !== 'undefined' && typeof console.trace !== 'undefined') console.trace(); 

Why not?

if (typeof console !== 'undefined'  && console.trace) console.trace(); 

Also, lazy conditions (or null-coalescing) are also cool.  Example:

x = x || getDefaultValueOfX(); // Basically only call getDefaultValueOfX if x does not have a value.  Synonimouse with ?? operator in C#

 

Loops

Iteration are a very personal thing some prefer to go backwards some forwards.  Some declare their 'i' before their 'for' some think this is very silly indeed.  This is how I loop.

for (var i = 0, e; e = array[i]; ++i) { ... }

Nice...  Oops, better mention a caveat here.  The termination expression here is e = array[i] which means that if the array contains: 0, '', null, undefined, false then the iteration will finnish prematurely.

But this syntax can also be used for lots of nice expressive statements like:

for (var i = 0, e, j = array.length - 1; e = array[i]; ++i; --j) { ... } 

How About:

for (var e; entries.length && (e = entries.shift());) { ... } // Awesome I hear you say?

etc, etc

 

Arrays

Arrays in javascript are very interesting, they are like an object with growths.  Some of those growths are very usefull but the fact that its still an object is pretty awesome also. So:

var x = [1, 2, 3 , 4];

x.max = function() {

 var m = Number.MIN_VALUE; 

 for (var i = 0, v; v = this[i]; ++i) { if (v > m) { m = v; } }

 return m;

}

How about (Continued from above):

x.length = 100;  // This actually increased the size of the array to 100 and filled in gaps with undefined

x.length = 2;  // This will shorten the array and 'delete' all enties above the specified index.

Something that needs to be mentioned here is the awesomeness of delete.  This marks a memory space for garbage collection so its a great way to ensure that something is infact 'deleted'.

Also, I highly suggest getting to know splice.  He can be a good friend.

 

Augmentation

The previous example (array x.max) is actually a form of augmentation but this concept can be taken even further and one of the pretties uses of this is a Crockfordian parasitic inheritance.  Let's have a look:

function Animal() {

 this.tallk = function() { return "Oink! Oink!"; }

}

 

function Dog() { // Dog will extend Animal parasitically (does that word exist?)

 var d = new Animal();

 d.talk = function() { return "Woooof, Grrrrrrrrrrr!"; }

 d.playDead = function() { return '.............'; }

}

alert(new Dog().talk());

There we go, we just implemented inheritance without ugly .prototype (s) and other nasties. 

 

Closures

If you ever have a chat to a Ruby developer they will probably bore you half to death with their preaching about the beaty of a closure, anyways JS has closures also, but javascript is a more practical language so we don't don't preach we just do.

Have you ever done this:

somearray.sort(function(a, b) { return a - b; });

We'll Array.sort takes in a cloure.  So closure is basically just a function that can be passed around and reused.  This is actually an amazingly powerful feature and can open a lot of doors when designing complex systems.  However, care must be taken when using closures, the context and hence the memory used up by the context of a function remains in memory as long as the closure is alive.  This is a common casue of JS memory leaks.

 

Hashtables (Dictionaries)

Objects are dictionaries.  This is actually a very usefull data structure so don't ignore it.

var dict = {};

dict['property1'] = prop1;

dict['property2'] = prop2;

dict['sub'] = function() { return this.propert1 + this.property2; };

 

Namespaces

Namespaces are usefull, they allow you to nicely modularise your code and prevent your code from clasing with other's code.  Namespacing in javascript is very easy.  I suggest the following approach:

// Create the namespace (using the uril finction below)

namespace('au.com.picnet.scripts');

 

// Add a class to the namespace

au.com.picnet.scripts.TestClass = function() {

 this.test = function() { alert('test'); }

};

 

// Instantiate the class and call test()

new au.com.picnet.scripts.TestClass().test();

 

// A safe namespace generator, can be called many times 

// with the same ns fragmens without fear of loosing objects.

function namespace(ns) {

 ns = ns.split('.');

 var current = window;

 for (var i = 0, n; n = ns[i]; ++i) {

 if (!current[n]) current[n] = {};

 current = current[n];

 }

}

 

Function Scope

The previous example of namespaces shows function scoping in action.  Function scope simply means that a function only has access its own members and its parent memebers (if it is nested).  So a parent funciton does not have access the the members of the nested function unless they are public.  This is actually a complex toic that I may explore further in its own article but for the time being I recommend reading this.

 

This!!

The this keyword is also a tricky beast especially when it can be manipulated with Function.apply and Function.call.  But generally this points to the current function (not the current function literal) or else the global scope.  Again too complex for this article but read this.

Note I generally try not to rely on 'this' very much.  If I need to access 'this' in future I generally create a temp variable that I can use:

var instance = this

This variable is created at a point I know that 'this' points to the right object and then don't worry about the technicalities.

 

Static Classes (Singleton, Utility Classes)

Object literals actually make great singletons.  Let see an example:

namespace('au.com.picnet.scripts');

au.com.picnet.scripts.Utilities = {

 add: function(x, y) { return x + y; },

 subtract: function(x, y) { return x - y; }

};

alert('add: ' + au.com.picnet.scripts.Utilities.add(1, 2) + ' subtrace: ' + au.com.picnet.scripts.Utilities.subtract(1, 2));

 

RegExp

The RegExp is an awesomly powefull object, it can make a 100 line parsing function vanish in a puff of elegance.  Howewer!!!!!  If you are anything like me, you need to use RegExps roughly 2-3 times a year.  The other times you just copy a previous use of the same regexp.  So when that time of year comes around you ask yoursel: How the hell do I do named groups again?

Well I have found that the best way to work with RegExs is to ignore them until needed.  When you do need a regex simply give yourself a 5 minute refresher here and make sure you test your regex thrououghly in places like here.  

I personally recommend not wasting too long getting good at RegExps as they are so rarely needed.  I have actually been good at RegExps several times but that all goes away... I have now accepted it.

 

Misc

- Always use '===' instead of '==' .

- Functions have a length attribute.  This is the length of expected parameters.

- Functions have an argumens array with all the arguments passed to the function, regardless of function signature.

 

Restraining the Beast

Javascript does give the developer too much rope, this is nice when trying to flex your creative powers but can become overpowering when working on large systems.  There are a number of tools which now allow you to try to tame this beast.  And at the top of the list is GWT (And other such projects).  However this is an extreme solution to this problem I personally like Javascript and don't really want to stop using it unless there are clear advantages on a project.  So some of the tools I use and look interesting are:

- Google's Closure Compiler : Adds some type safety to your beast (with annotations)

- FireBug : Don't leave home without it

- DOM / Ajax Helper Libs (jQuery, dojo, prototype, closure libs, etc): A must for cross browser development (I personally use jQuery as it seems to have won the popularity contest and regardless what the 'hardcore' tell you, this is actually very important)

 

The next generation of JS IDEs are also very exiting, leading this list are:

- WebStorm

- Visual Studio 2010

 

So Notepad++'s domination of the js development world may be comming to an end soon.  Ahhh I actually have dreams of accurate type inferrence in real time for a JS IDE.

 

Thanks

Guido Tapia

Software Development Manager

PicNet Pty Ltd


How to prevent 'Stop running this script' message in browsers

Posted on clock March 4, 2010 07:23 by author guido

Avoiding the 'Script taking too long' (all browsers have some form or another of this) message in browsers is relatively simple. You just have to make sure the browser knows you have not created an endless loop or recursion. And the easiest way to do is is to just give the browser a breather in between long running tasks.

So how would we go about this.  Well the simplest solution is to just break up your task into mutliple smaller tasks with a setTimeout in between these tasks.  The utility class below does just this:

Utility Class


RepeatingOperation = function(op, yieldEveryIteration) {
var count = 0;
var instance = this;
this.step = function(args) { 
if (++count >= yieldEveryIteration) { 
count = 0;
setTimeout(function() { op(args); }, 1, [])
return;
}
op(args); 
}; 
};

So how do we use this class, lets say we have the following code which is giving us a jerky browser and occasionally displaying those horrible 'Stop running this script' message:


// initdata is just an array of numbers (a very very large array)
var test1 = new Array(initdata.length);
for (var i = 0; i < initdata.length; i++) { test1[i]  = initdata[i] * 2; } // Double each item in the initdata array
continueOperations();

To use the utility class above we would change the code to this:


var test2 = new Array(initdata.length);
var i = 0;
var ro = new RepeatingOperation(function() {
test2[i] = initdata[i] * 2;
if (++i < initdata.length) { ro.step(); }
else { continueOperations(); }
}, 100);
ro.step(); 

That's it, a little bit more code, an extra closure, so not pretty but I think a relativelly stylish solution to a nasty problem.  Note: Remember this will also give you a much more responsive browser during execution of this expensive code also.

Note: This solution is used in the Mouse Eye Tracking system.  So it is production ready (at your own risk tho).

Thanks

Guido Tapia

Software Development Manager

PicNet Pty Ltd

 


Game of Life in JQuery

Posted on clock November 10, 2009 10:56 by author guido

Hi All,

I've just done a tutorial video on JQuery, I chose to hack together a quick version of the Game of Life.  This tutorial aims to show how JQuery can help you modify the DOM on the fly and do some nifty manipulations.  I hope you enjoy.

Please let me know if there are other JQuery topics you would like to see covered in a 'practical' style video.

Demo


Part 1

Part 2

Part 3

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd


JQuery Table Filter Plugin

Posted on clock June 29, 2009 07:32 by author guido

This project has moved. New Home Page

Update 1/Mar/2010
The home page for this project is now at http://www.picnet.com.au/picnet_table_filter.html 

Was this plugin useful for you?

The PicNet Table Filter is free, so we appreciate if you would help us out by recommending us on LinkedIn.

Alternatively, write us a review on Google Places mentioning how the Table Filter helped your project. Finally, you can follow us on Twitter or subscribe to our YouTube channel.

Update 11/Feb/2010
I will be moving this project to its own page with the source code at github very shortly. This is because this project has taken on a life of its own and I personally don't want to be the only mantainer (having very limited time). So I'm sending a call out to anyone that wants to participate on the ongoing development of this project. Please email me (guido.tapia@picnet.com.au) if you would like to be a developer of this project. Note: I assume very little time will be required. 

Once the new site is ready this blog post will be sanitized (links removed and comments closed) as everything will live on the new site.

Introduction

This plugin adds column filtering capabilities to a regular <table> by adding a row to the <thead> section of a table and adding filters that allows real time filtering of tabular data.  Download this demo bundle for a quick start.

Note: We use this library in the production of many of our custom software development projects so it is production ready.

Demo

A simple demo page.

Getting Started

This plugin uses several other popular plugins so you will need to download these plugins before starting.

You can also use this packed version of the scripts. These plugins will then need to be referenced in the <head> section of your page.


<script type="text/javascript" src="Scripts/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.cookie.js"></script>   
<script type="text/javascript" src="Scripts/picnet.jquery.tablefilter.js"></script>

Or (For Production Code)


<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.3.2.min.js" type="text/javascript"></script>    
<script type="text/javascript" src="Scripts/scripts-pack.js"></script>  

This plugin will then create the filters in a row in the THEAD element of the table so add this if it is not already there.


<table id='demotable'>        
    <thead>
        <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>        
    </thead>
    <tbody>
        <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
        ....
    </tbody>
</table>

Hook in your table when the document is loaded.


$(document).ready(function() {
    $('#demotable).tableFilter();
});
 

Filter Types

Currently the picnet.jquery.tablefilter.js only supports two kinds of filters.  The first and default is 'text' which just produces a text box for context sensitive text matches.  The second is 'ddl', this produces a drop down list that allows the selection of a single item in that list.  To specify the filter type simply add "filter-type='ddl'" in the header cell of the required column.  I.e.


<table id='demotable'>        
    <thead>
        <tr><th>Col1</th><th>Col2</th><th filter-type='ddl'>Col3</th></tr>        
    </thead>
    <tbody>
        <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
        ....
    </tbody>
</table>

Options

We can also pass an options object to control some basic behaviours of the tableFilter. The current supported options are.

  • additionalFilterTriggers: These are additional input controls that will be hooked in to the filter code. Currently only type='text' and type='checkbox' controls are supported.
  • clearFiltersControls: Controls that onclick will clear all of the filter values (including additionalFilterTriggers).
  • matchingRow: function(state, tr, textTokens) { ... } These event will allow you to determine wether a matching row is actually correctly matching. This event will be called when a row is considered to have matched the filter, returning false will override this assumtion and hide the row from the results.
  • matchingCell: function(state, td, textTokens) { ... } This event behaves the same as the one above but allows more granular overriding capabilities. Returning false will again override the default match logic.

Example 1: Adding an additional whole row filter

Lets suppose that appart from having column filters we also want to have a quick find style filter that matches any cell in a row. To do this simply add the textbox to the additionalFilterTriggers array. TODO


<head>
    ...
    <script type="text/javascript">  
    $(document).ready(function() {
        // Initialise Plugin
        var options = {
            additionalFilterTriggers: [$('#quickfind')]
        };
        $('#demotable).tableFilter(options);
    });
    </script>
</head>
<body>
    Quick Find: <input type="text" id="quickfind"/>
    <table id='demotable'>        
        <thead>
            <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>        
        </thead>
        <tbody>
            <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
            ...
        </tbody>
    </table>
    ...

Example 2: Adding an additional checkbox filter

Let’s suppose that we have a Boolean column that we want to filter. The best way to do this will be to add a checkbox filter so let’s do this. We will keep the quick find filter to show how to have multiple additional filters. 


<head>
    ...
    <script type="text/javascript">
    $(document).ready(function() {
         // Initialise Plugin
        var options = {
            additionalFilterTriggers: [$('#onlyyes'), $('#quickfind')],
            matchingRow: function(state, tr, textTokens) {
                if (!state || state.id != 'onlyyes') { return true; }
                return state.value != true || tr.children('td:eq(2)').text() == 'yes';
            }
        };
         $('#demotable').tableFilter(options);
    });
<

p>    </script>
</head>
<body>    
    Only Show Yes: <input type="checkbox" id="onlyyes"/>
    <br/>
    Quick Find: <input type="text" id="quickfind"/>
    <table id='demotable'>        
        <thead>
            <tr><th>Col1</th><th>Col2</th><th>Boolean Col3</th></tr>        
        </thead>
        <tbody>
            <tr><td>Value 1</th><th>Value 2</th><th>yes</th></tr>        
            ...
        </tbody>
    </table>
    ...

Example 3: Clear Filters

Having a clear filters button comes in very handy, especially when you have a table with a larger number of columns. To add this functionality simply add your clickable control to the clearFiltersControls array. 


<head>
    ...
    <script type="text/javascript">
        $(document).ready(function() {        
            // Initialise Plugin
            var options = {
                clearFiltersControls: [$('#cleanfilters')],            
            };
            $('#demotable').tableFilter(options);
        });
    </script>
</head>
<body>
    <a id="cleanfilters" href="#">Clear Filters</a>
    <br/>    
    <table id='demotable'>        
        <thead>
            <tr><th>Col1</th><th>Col2</th><th>Col3</th></tr>        
        </thead>
        <tbody>
            <tr><td>Value 1</th><th>Value 2</th><th>Value 3</th></tr>        
            ...
        </tbody>
    </table>
...

Known Limitations

  • More custom filter types needed (such as multi select lists, radio lists, etc)
  • No support for custom additional filters other than checkbox.

Guido Tapia

Manager - Custom Software Development

PicNet Pty Ltd