Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Monday, 18 December 2006

Date reconverter

This is the date reconversion utility that I mentioned in a previous post. It takes similar arguments to the string.toDate() extension posted being in format dmy to represent day/month/year with this one having the optional argument t to denote the time. double a character means the result will be padded (so if the month is april using m will return 4 but mm will return 04). Pretty self explanatory, but I like the slickness of it. It could be better improved to organise times being formatted before dates, maybe something to consider at a later date.

/* Convert a date into a string.
* The format argument denotes the format (including padding zeros) the
* date is returned as. d - day, m - month, y - year, t - time.
* Double characters or quad y for year) will pad/extend that number.
* Optional: argument d_l is the date delimiter, t_l is the time delimiter.
* @param (String) format
* @param (String) d_l (Optional)
* @param (String) t_l (Optional)
*/
Date.prototype.convert = function(format, d_l, t_l) {
    var d_l = d_l || "/",
        t_l = t_l || ":",
        date = [],
        pad,
        d = this;
        
    pad = function(n) {
        return (n < 10) ? String("0"+ n) : n;
    }
    
    format = format.replace(/(m+)|(d+)|(y+)|(t+)/gi, function(s) {
        switch(s) {
            case "d": date.push(d.getDate()); break;
            case "dd": date.push(pad(d.getDate())); break;
            case "m": date.push(d.getMonth()); break;
            case "mm": date.push(pad(d.getMonth())); break;
            case "y": date.push(String(d.getFullYear()).substring(2, 4)); break;
            case "yy": date.push(String(d.getFullYear()).substring(2, 4)); break;
            case "yyyy": date.push(d.getFullYear()); break;
            case "t": date.push(d.getHours()+ t_l + d.getMinutes()); break;
            case "tt": date.push(pad(d.getHours()) + t_l + pad(d.getMinutes())); break;
        }
    });
    
    return (date.length < 3)
        ? null : (date.length == 3)
            ? date.join(d_l)
            : date[0]+d_l+date[1]+d_l+date[2]+" "+date[3];
}


// Usage:
var strDate = "4::13::1976 10.30";

// the previous post String extension to create a date object
var objDate = strDate.toDate("mdy");

// Use this date convert extension
var newStrDate = objDate.convert("ddmmyytt", ".", ":"); // outputs 13.04.76 10:30

Wednesday, 13 December 2006

I need a date!

OK, so the title of the post is catchy, but this isn't about an urgent yearning for the future Mrs Narg - actually there's always an urgent yearning for the future Mrs Narg but let's not go there. This is about converting a string to JavaScript date object.

The concept is you have a string and you just call this method with the sequence the day/month/year appear in (d, m, y respectively). This is regardless of any delimiters of your date (delimeters being the characters between the numbers) so this will work the same way for dates in formats such as: 13/04/1976, 1976-04-13, 04::13::1976
It's pretty neat, a regular expression just finds the numbers in the sequence and then uses the format (dmy, mdy, ymd or ydm) to find which number refers to what. It then has a look to see if a time has been passed. Again the delimiter splitting the hours from the the minutes is not important, but the order must be hours then minutes (ir hh:mm or h/m or hh-mm). If no time is found, then the time defaults to 00:00 on the date supplied. All this information is then used to create a standard date object and return it - if the process fails at any stage, the method returns null.


/*
Copyright (C) 2006 Martin Rudd

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
*/
String.prototype.toDate = function(format) {
    if(/(\d{1,4})[^\d]+(\d{1,4})[^\d]+(\d{1,4})([^$]*)/i.test(this)) {
        var date;
        switch(format) {
            case "dmy":    date = { year: RegExp.$3, month: RegExp.$2, day: RegExp.$1 };
            break;
            case "mdy": date = { year: RegExp.$3, month: RegExp.$1, day: RegExp.$2 };
            break;
            case "ymd": date = { year: RegExp.$1, month: RegExp.$2, day: RegExp.$3 };
            break;
            case "ydm": date = { year: RegExp.$1, month: RegExp.$3, day: RegExp.$2 };
            break;
        }
        
        if(typeof date === "object") {
            var time = RegExp.$4.replace(/^\s*|\s*$/g, "");
            
            if(time.length > 0) {
                if(/(\d{1,4})[^\d]+(\d{1,4})/.test(time)) {
                    date.hours = RegExp.$1;
                    date.minutes = RegExp.$2;
                }
            }

            date.hours = (typeof date.hours != "string") ? 0 : date.hours;
            date.minutes = (typeof date.minutes != "string") ? 0 : date.minutes;
            
            return new Date(date.year, date.month, date.day, date.hours, date.minutes);
            
        } else {
            return null;
        }
    } else {
        return null;
    }
}


Feel free to have a play. Tomorrow I'll post up a method turning the JavaScript date back into a string in different formats.

Tuesday, 12 December 2006

Joining strings

We've all been there before - concatenating strings of html, but which way is quicker?

1) Recursive concatenation.
var html = "<html>" + "<head>" + "<title>";

2) Append to the variable.
var html = "<html>";
html += "<head>";
html += "<title>";

3) Join the array
var html = ["<html>", "<head>", "<title>"].join("");

Smart engines such as SpiderMonkey (the basis for Netscape's original JavaScript engine - leading to Netscape, Firefox, etc) would use exactly the same underlying code for examples 1 and 2 - no speed difference at all. JScript in example 2 however would look up the html variable each time and use an intermediary to store the new values before discarding the old ones. So there would be a speed differential in JScript where example 1 is quicker than example 2.

The fastest string concatenation is using option 3 - this is down to the array's internal string builder facility which allows for much faster string manipulation. Of course it's only going to make a big difference when contactenating strings over many iterations - such as creating a large html table. Over a very small number of iterations the difference is so negligable as to be inconsequential.

Thursday, 23 November 2006

Number fun

Numbers are pretty interesting things, as well as the obvious mathematical use people also attribute emotional, psychological, mythological and religious reactions to certain numbers. Everyone has numbers they like and don't like, history and superstition show that westerners perceive the number 7 as not only lucky but also there are associations with cognitive psychology whereas the chinese see the number 8 as especially fortuitous. Funky stuff. In fact numerology explores this relationship between numbers and other systems (religious, physical, living, etc). My study into this is fairly limited, but it's always been interesting playing around with numbers and I've a stack of JavaScript number object extensions that I carry around in an html file wherever I go to work.

So here they are. I can't take full credit for all of these, I've based some of them on other snippets of code I've found around the place. Notably from codingforums.com so thanks to all who have contributed. I should point out that there's not much explaning that will be done as to why they work - they've been chopped right down to the bare minimum of overhead in most cases and work beautifully, but often look complex. I may well post up another time how they work in more detail.

1) First up is a classic. Rounding a number to a specified number of decimal places. It takes an optional argument n for the number of decimal places to round to. If no argument is supplied, the number will be rounded to 2 decimal places.

Number.prototype.toDecimals = function(n) {
  var n = (isNaN(n)) ? 2 : n;
  var nT = Math.pow(10, n);
  function pad(s) {
    s = s || '.';
    return (s.length > n) ? s : pad(s + '0');
  }
  return (isNaN(this)) ? this : (new String(Math.round(this*nT) / nT)).replace(/(\.\d*)?$/, pad);
}


Usage:
var intNumber = 9.23423;
var intRounded = intNumber.toDecimals(); // output: 9.23
var intRoundedToFourPlaces = intNumber.toDecimals(4); // output: 9.2342

2) Make an ordinal string (eg 1st, 2nd, 3rd) from a number. I use this a lot in date formatting. The argument n is just a locally declared variable, this function does not need any arguments passed to it.


Number.prototype.toOrdinal = function(n) {
  return ( this + ["th","st","nd","rd"][(!(((n = this % 10) > 3) || (Math.floor(this % 100/10) == 1))) * n] );
}


Usage:
var intNumber = 13;
var intOrdinal = intNumber.toOrdinal(); // output: "13th"

3) Convert a decimal number (also known as base ten or denary number) to hexidecimal (base 16 or hex) string. Hexidecimal is the numeral system that computers use. This is very useful for html colour codes which use 3 pairs of hexidecimal values to dictate the red, green and blue mix of the colour (so #CC130F is actually - CC 13 0F).

Number.prototype.toHexidecimal = function() {
  return this.toString(16).toUpperCase();
}


Usage:
var intNumber = 28;
var intHexidecimal = intNumber.toHexidecimal(); // output: "1C"


4) Convert a decimal number to binary. This is used the least out of the previous 3 number extensions, but it's included because it's elegant!

Number.prototype.toBinary = function() {
  return this.toString(2);
}


Usage:
var intNumber = 13;
var intBinary = intNumber.toBinary(); // output: 1101

You can also use these by putting parentheses (round brackets) around the number and calling the method. For example (13).toBinary(); outputs 1101, (40).toOrdinal(); outputs "40th", etc.

You may well notice that the 3rd and 4th number extensions (toHexidecimal() and toBinary()) use the native JavaScript object toString() method. When used with JavaScript numbers, this toString method allows you to pass an argument called a radix. In pretty much every numeral system we use, a radix refers to the number of unique digits that the chosen numeral system can use (including 0). So in the case of toBinary() we pass a radix of 2 because there are two digits that binary can use 0 and 1. In the case of decimal there are 10 they are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 and in the case of toHexidecimal() there are 16 which are 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F. The letters A-F are used in hexidecimal to complete the number of unique digits for that numbering system (the decimal equivelant would be 10-15 but as all those numbers (0, 1, 2, 3, 4, 5) have been used previously, they need to be replaced with unique digits).

So go, have fun with the numbers, be nerdy and spread the word!

Tuesday, 21 November 2006

CSS image flickering solved in IE

There has been a problem for many years that most of us have come across developing for Internet Explorer with background images "flickering" when the cursor is hovering over them. (here's an example). This is due to to Internet Explorer checking for a new version of the background image declared in the background-image css attribute when the mouse hovers over the tag. The flicker issue may also be accompanied with the hourglass flicking on or even no image flicker, but the hourglass flickers!

<script type="text/javascript" language="javascript">
/*@cc_on @*/
/*@if (@_jscript_version >= 4)
document.execCommand("BackgroundImageCache", false, true);
/*@end @*/
</script>

Essentially, if you include this script somewhere in your page (best towards the top) then it will resolve this problem. Banzai!

The comments with all the @ symbols are actually JScript (Microsoft's version of JavaScript) conditional commenting. In simple terms, only IE will see and execute this code. In more complex terms it means only the IE compiler will read and compile this code. This means that should you have large forks in your script - one to deal with IE and another to deal with any other browsers - you can often get large performance returns from using conditional compiling. There's a good article on javascriptkit.com about conditional compilation of JScript.

I can't take credit for this solution - MisterPixel came up with the goods looking into DHTML behaviours in IE with regards to another problem (a bit like Fleming discovering penicillin!).

Thursday, 16 November 2006

Registry hacking

Note: This is Internet Explorer only as it deals with ActiveX and modifying the system registry.

Recently I've been writing a few scripts to change values in the system registry. In actual fact, you use a few different technologies to achieve something that looks very simple. This script reads then sets the home page for Internet Explorer via the registry. However you can edit any registry value you wish to using this method.

Background
Firstly what is the registry? In simple terms, the registry is a database that stores settings and options for Windows and contains information for all the hardware, software and preferences of the PC (http://en.wikipedia.org/wiki/Regedit). This script uses a combination of JScript and ActiveX in a Windows Script host environment to edit those bits of information in the registry. JScript is Microsoft's Active Scripting implementation of ECMAScript (http://en.wikipedia.org/wiki/Jscript). Basically it's their version of JavaScript, but with lots of add-on features. These "add-ons" also rather nattily work in any Windows Script Host environment - and that's been shipped by default with every version of Windows since Windows 98 or with Internet Explorer 5+. Further information: http://en.wikipedia.org/wiki/Windows_Script_Host. We can use this JScript to create an ActiveX control to pass information from our script into the registry. ActiveX is simply as mechanism for passing information around a Windows computer. All in all, pretty neat eh?

Here's my script:
<script type="text/jscript" language="jscript">
var objShell = new ActiveXObject("WScript.shell");

/* Get the current home page */
var strRegKey = "HKCU\\Software\\Microsoft\\Internet Explorer\\Main\\Start Page";
var strCurrentHomepage = objShell.RegRead(strRegKey);

/* Set a new homepage */
objShell.RegWrite(strRegKey, "http://nargster.blogspot.com/");

</script>

Let's go through it.
The script attributes
<script type="text/jscript" language="jscript">

These are set to jscript because this script is only to work in IE it's not vital, but it's good a good habit to get into.

Create an Windows Script Host (WScript) shell object
var objShell = new ActiveXObject("WScript.shell");

OK, so we're going to ask the script to create a new ActiveX object (as mentioned, this is just an information carrier) to pass information to a particular target - in this case the Windows Script Host (WScript) shell. The shell is simply interface that enables access to the inner workings of the computer - we need to create this shell object in our script to access the registry.

Accessing the registry
var strRegKey = "HKCU\\Software\\Microsoft\\Internet Explorer\\Main\\Start Page";
var strCurrentHomepage = objShell.RegRead(strRegKey);
objShell.RegWrite(strRegKey, "http://nargster.blogspot.com/");


Now we've created a shell object, we can access the properties and methods of that object. Two of its methods are called RegRead and RegWrite - they read and write the registry respectively. The example shows the arguments required for these two methods. In both we pass the registry path of the registry item we wish to edit, making sure that we replace any single backslashes \ with a double backslash \\. This is because the backslash character in JScript is special - it's an escape character. The strRegKey string is the path to the value we want to change, you can find more information about how this string is built by looking through the registry using regedit, explained below. It's easy to see how the string relates to the structure of the registry, it's like a filesystem folder path.

Regedit - the registry editor
So you want to find out what the registry looks like to browse through. I'll not kid you - it's massive. You can use regedit, the registry editor (Start Menu --> Run, then type regedit and hit enter or run regedit.exe or regedt32.exe in your Windows directory) to have a look around and adventure. The registry structure is too detailed to go into here, but Wikipedia do an excellent job of it: http://en.wikipedia.org/wiki/Regedit

A last word just on security
It does seem incredible that Microsoft would create a web browser that could run scripting to read and write the system registry, but that's what they've done. They've tried to correct this problem in IE7 by not allowing the creation of ActiveX controls by default - users must enable this manually (with accompanying nasty messages about potential insecurities). In other supported versions of IE (IE3 - IE6) the default behaviour is that this simply runs with an ActiveX warning message. You can get around these warnings by saving the html file with an hta extension, turning the html file into an HTML application (MSDN). This .hta file only runs locally on a machine and runs without the strict security model the browser uses - no nasty error messages!

Play around with the registry - you could potentially damage something, but stick to the simple stuff and work your way up and it should all be good. Using .hta files is good because it opens all sorts of potential for html/scripting without security restrictions, so you can make cross-domain AJAX calls - something which is not allowed in a webpage) as well as other funky HTML applications to change the settings and tailor your computer.

Windows Script Host programming reference
There's loads of methods and properties of the shell object - you're not limited to reading and writing stuff to the registry - you can set/retrieve/delete user information, network and printer settings, read and write files and much more. You can find details of this at devguru.com in their Windows Script Host reference:
http://www.devguru.com/Technologies/wsh/quickref/wsh_intro.html

Tuesday, 14 November 2006

Garbage Collection

Thought I'd post up a bit I wrote at work discussing differences in memory handling and garbage collection in different browsers.

Background
Microsoft's implementation of ECMAScript is actually called JScript (not JavaScript), and it's behaviour with regards to garbage collection differs from the original implementation of JavaScript in SpiderMonkey (SpiderMonkey is the name for the first JavaScript engine written by Netscape, Firefox is based on this engine). It's worth noting that the JScript/JavaScript engine does not itself provide a host environment for the DOM - they are two separate structures that exist together, but can logically exist apart.

The main difference
IE uses non-generational mark and sweep garbage collection versus SpiderMonkey's generational mark and sweep garbage collection. The "mark and sweep" bit means that each object (either JScript or JavaScript) has an attribute that is set to 1 if it is to be collected and 0 if it is not. As the generational/non-generational bit of the name implies, what it means is that SpiderMonkey will find older objects first and clean them out (generational), whereas IE will do this fairly indiscrimately and just find JScript objects in memory and check to see whether to garbage collect them (non-generational). Simply put SpiderMonkey will push the objects to be collected to the bottom of the memory heap (http://en.wikipedia.org/wiki/Heap_(programming)) and then knows to grab the bottom of the pile to free memory, whereas JScript will throw objects (relatively) randomly onto the heap and then pick through all of them individually checking to see if that object needs collecting. As you can imagine there's an impressive performance lean towards generational garbage collection.

Implications
Because of the relationship between the DOM and the JScript/JavaScript engine, stacking objects in memory becomes very important. As you can imagine, keeping less objects in memory now has real performace implication in IE - especially circular references between the engine and the DOM such as an array of nodes - an example of this problem would be memory leaking through event handlers in the DOM (http://www.jibbering.com/faq/faq_notes/closures.html#clMem) - in fact this problem surfaces with any sort of large numbers of data types/objects held in memory at one time. It also should promote forced memory handling when resources can become free, rather than simply waiting for automatic garbage collection to be initiated (statements such as "myArray = myString = myNumber = null") to make sure the object has the least memory allocated to it after use and the automatic garbage collection then becomes much quicker.

Links to more info
Garbage collection: Wikipedia Garbage Collection
SpiderMonkey: Wikipedia SpiderMonkey
Garbage collection models: North Eastern University