AngularJS

I've started getting into Bootstrap and AngularJS. Look for posts on those topics soon. Bootstrap is fun because even I can make a decent looking app with pretty much no savvy for design, and Angular is fun because it forces you into a new way of thinking, and getting that stuff to work and "getting it" is really what I strive for. The moment something clicks... it's a drug to me.

Saving State in Javascript and AJAX

We're doing something cool in work, to do with resource scheduling in a nice ajax-y, jQuery-UI-ey way.  There are a set number of filters to apply to get the view of the resources you want, which can include Department (for example, Development, Front-End, Client Services, Marketing), the Employee themselves, Employee Roles to show Senior Developers etc, Client and Project. The problem was, these are all filtered via AJAX, and refreshing the page would cause you to lose your filters.

One way that developers solved this was by keeping the state in the "hash" portion of the URL.  The most prevalent method of this was called the "Hashbang" which would add the hash (octothorp) and an excalamation point (! - the "bang").  This is easy but could lead to messy / long URL.

Another method that is pretty convenient is to set a cookie containing the parameters. The downside of this is you can't send the same view that you're looking at to a coworker. That cookie is on your computer only.

I couldn't decide which one to implement so I decided to do both.

    var serializers = {};

    serializers.hash = function(){
        this.serialize = function(str){
            window.location.hash = str;
        };         this.prepDeserialize = function(){
            var hash = window.location.hash;
            return hash == null || hash.indexOf("#") != 0 ? "" : hash.substring(1);
        };
    }     serializers.cookie = function(){
        this.serialize = function(str){
            window.Cookie.set("ajaxState_serialize", str);
        };         this.prepDeserialize = function(){
            return window.Cookie.get("ajaxState_serialize");
        };
    }

I have a cookie helper class which wraps what you can find on quirksmode.org.  If you want to use this code, you can provide your own cookie serializer, your own custom serializers, or whatever, without changing the rest of the code.

The rest of the code is just adding and subtracting values from the serialized data. To call it, it's simply this:

                var data = $.fn.projectFilter.getFilterData($wrap);
                window.AjaxState.serialize(data, true);

So you get the filter object and serialize it. The true on the call to serialize just says to "commit it", which means to write the data to the cookie or the hash on the same call. I've put this code up on this site, you can download it.

Javascript Functional Programming

In work, I was recently tasked with a data comparison project. A bunch of data was getting duplicated. These records include user first and last names, their phone, email, company.  The master file was a list of these same users but they were assigned "card id" because they were already customers.

The method was to find a match for name (first and last) and if the email didn't match, then separate it out. Then find a match for email, and if the name didn't match, separate it out.

You can imagine this logic:

Go through each line... 
var matches = core.filter(function(a){ return a.firstName == line.firstName && a.lastName == line.lastName; }); // match names 
if (matches.length == 1){ var matchingEmail = matches.filter(function(a){ return a.email == line.email; });
    if (matchingEmail.length == 1){ add it to results }
     else separate it out;
}

And do the same, checking email first. The main feature of Object Oriented Programming is to abstract out data and functionality so that different objects can behave the same way in a system. The main idea of functional programming is that the process can be abstracted out.

What I'm basically doing is, match the line to the map based on some values, if there are any matches, find matches within that result which match some other value. If that result is 1, then we've found a good match, and repeat with the comparison methods swapped.

Or, even more abstractly... running a comparison function, getting results, and running another comparison function to filter the results further.

Let's define our comparison functions:

var compareName = function(a) { return a.firstName == line.firstName && a.lastName == line.lastName; };
var compareEmail = function(a) { return a.email == line.email; };

We can create a method to run these comparisons. It will need the line, the master list, and the two comparison functions.

function compare(line, masterList, comparison1, comparison2)

And then we can call it like so:

compare(line, masterList, compareName, compareEmail);
compare(line, masterList, compareEmail, compareName);

Voila!

I'm an IDIOT!!

I spent a ton of time trying to write a syntax parser for a meta-language which would be parsed by Javascript.  I just replaced a lot of confusing logic with about 40 lines of code.

First, Javascript is dynamic and has stuff built in that can evaluate arbitrary code passed in via a string.

I'm not talking about eval().

Function!

However, my syntax looks like this:  Hello {{page.user == null ? 'Anonymous' : page.user.firstName }}

So, we need to know what "page" is in the context of the function.  I still have to parse out top level variables.  In the code above, it will get "page" as a top level variable.

Then, I build up the function:

var f = new Function(vars[0], body);

"body" is actually modified, I set it to "return " + body;  So that I can do {{ page.user == null ? 'Anonymous' : page.user.firstName }} and it will return the display name instead of undefined, the default behavior of a void function.

I have to count up the number of variables used, and build the function accordingly.  Currently, this is a switch statement.

switch (vars.length){
     case 0: f = new Function(body); break;
     case 1: f = new Function(vars[0], body); break;
     case 2: f = new Function(vars[0], vars[1], body); break;
}

Luckily in my code, there aren't more than 3-4 "top level" variables, including globals like "Array" and "String".

Here's the variable parsing part:


var shared = require("./shared"); require("strings"); var constants = { "true": true, "false": true, "null": true }; var lookup = {}; this.getVariables = function(body){ if (body in lookup) return lookup[body]; var vars = []; var instr = false; var instrch = null; var buf = ""; var toplevel = false; var result = null; for (var i = 0; i < body.length; i++){ var ch = body.charAt(i); switch (ch){ case "'": case "\"": instr = ch != instrch; instrch = instrch == null ? ch : (instr ? instrch : null); break; } if ((!instr && shared.tokenSeparator.test(ch)) || i == body.length-1){ if (i == body.length-1) buf+= ch; if (!toplevel && (result = shared.variable.exec(buf)) != null && !(result[1] in constants)){ if (!vars.some(function(d){ return d == result[1]})){ vars.push(result[1]); toplevel = true; } } buf = ""; } else if (instr) buf = ""; else buf += ch; if (toplevel && (instr || (shared.tokenSeparator.test(ch) && ch != "." && ch != "]"))) toplevel = false; } lookup[body] = vars; return vars; }

And here's the evaluation part:

var syntax = require("./syntax"); var shared = require("./shared"); var lookup = {}; var Evaluator = function(globals){ this.globals = globals; } Evaluator.prototype.evaluate = function(body, context){ body = shared.replaceComps(body); var vars = syntax.getVariables(body); var args = []; body = "return " + body; for (var i = 0; i < vars.length; i++){ if (context && vars[i] in context) args.push(context[vars[i]]); else if (this.globals && vars[i] in this.globals) args.push(this.globals[vars[i]]); } if (body in lookup){ return lookup[body].apply(null, args); } var f = null; switch (vars.length){ case 0: f = new Function(body); break; case 1: f = new Function(vars[0], body); break; case 2: f = new Function(vars[0], vars[1], body); break; case 3: f = new Function(vars[0], vars[1], vars[2], body); break; case 4: f = new Function(vars[0], vars[1], vars[2], vars[3], body); break; } var result = null; if (f != null){ result = f.apply(null, args); lookup[body] = f; } return result; } this.Evaluator = Evaluator;

shared.js has a regular expression, a map (for old syntax considerations), and a function to replace some old ways of doing things with the new, pure Javascript way of doing it.

this.replCompRegex = / (eq|ne|gt|lt|gte|lte) /; this.replCompMap = { eq: "==", ne: "!=", gt: ">", lt: "<", gte: ">=", lte: "<=" }; this.replaceComps = function(body){ var res = null; while ((res = this.replCompRegex.exec(body)) != null){ body = body.replace(res[1], this.replCompMap[res[1]]); } return body; }

Javascript Peculiarity

I was trying to write a syntax parser, and everything was going just great until I came across this little tidbit. In parsing this syntax:

obj.prop1.prop2.substring(0,1) I'd parse and evaluate obj, then find properties in it like so: var currentContext = null; code.split("."); for each (token in split string){ if (currentContext == null) currentContext = evaluate(token); else if (token in currentContext) currentContext = currentContext[token]; }

Evaluate executes code and returns objects within a context global to the method call, not the local context, which I call here, "currentContext"

But then I got an error trying to do stringProperty.substring(0,1). Can't call "IN" on a string? So I'm like, ok, let me try something else

if (token in Object.getPrototypeOf(currentContext)

And guess what... That shit don't work! Cannot call getPrototypeOf on a non-object. But it's a string?!

So I just ended up doing, if (token in String.prototype), just to say F YOU JAVASCRIPT!!! Otherwise I love Javascript. If you have any insight on this, PLEASE feel free to leave a comment.

I wrote up a JSFiddle for it, please link your own in the comments

Solving [WordHero]

I took pretty much a brute force attack at coming up with this app that solves [WordHero]. It is pretty efficient and takes longer to type in the letters of the puzzle than for it to solve it.

Here's how I went about it.

So, you get a puzzle with 16 (or so, as you can see with the Qu block) letters arranged in a 4x4 grid.  Obviously this is a dictionary brute force attack, in the most literal sense.

What I do is start at the top left block, finding words that start there, then when all options are exhausted, move onto the next block and find all words that start there, and so on until we've covered all blocks. I wrote this solution in Node.js. First, there is the LetterBox class:

var LetterBox = function(letter, row, col){ this.letter = letter; this.row = row; this.col = col; this.used = false; } LetterBox.prototype.clone = function(){ var lb = new LetterBox(this.letter, this.row, this.col); return lb; }

The letter box can only be used once during a word solve. The next is the Board, which consists of LetterBoxes

var Board = function(str){ this.originalString = str; this.makeBoard(str); this.letterBoxLookup = {}; var self = this; this.letterBoxes.forEach(function(lb){ self.letterBoxLookup[lb.row + "" + lb.col] = lb; }); this.rows = 4; this.cols = 4; }

I implemented clone on both the Board and LetterBox classes.
The last piece is the BoardSolver class. We'll just look at two functions of it:
Solve:

BoardSolver.prototype.solve = function(max){ for (var i = 0; i < this.board.rows; i++){ for (var j = 0; j < this.board.cols; j++){ var boardinstance = this.board.clone(); this.getWords("", i, j, boardinstance, this.dictionary); } } var list = []; for (var w in this.foundWords) list.push(w); return list; }

And getWords:

BoardSolver.prototype.getWords = function(cur, row, col, boardinstance, dictlocal){ var letter = boardinstance.getLetter(row,col); if (letter == null || letter.used) return; var curlocal = cur + letter.letter; var potlocal = this.potential(curlocal, dictlocal); if (potlocal.length == 0) return; // no potentials down this path var wordlocal = curlocal.length > 2 ? this.matches(curlocal, potlocal) : []; var self = this; wordlocal.forEach(function(w){ if (!(w in self.foundWords)) self.foundWords[w] = w; }); letter.used = true; //var recurseClone = boardinstance.clone(); // n,s,e,w this.getWords(curlocal, row, col-1, boardinstance.clone(), potlocal); this.getWords(curlocal, row, col+1, boardinstance.clone(), potlocal); this.getWords(curlocal, row+1, col, boardinstance.clone(), potlocal); this.getWords(curlocal, row-1, col, boardinstance.clone(), potlocal); // diagonals this.getWords(curlocal, row-1, col-1, boardinstance.clone(), potlocal); this.getWords(curlocal, row+1, col+1, boardinstance.clone(), potlocal); this.getWords(curlocal, row+1, col-1, boardinstance.clone(), potlocal); this.getWords(curlocal, row-1, col+1, boardinstance.clone(), potlocal); }

So, while we're recursing, we'll get the current potential word (previous cur + this letter) and see if there are any potential words, words that start with the letters in curlocal. If there are no potential matches, stop recursion. If there are potential matches, keep going, also, store the current matched words at the current length (e.g. "break" is found on the way to finding "breaking")

To speed things up a bit, I only then search the potential list in the future attempts to narrow it down. Notice I'm passing the potlocal (potential local dictionary) into getWords on recursion.

To use the app currently, I just modify the string of characters. They are entered as follows (for example, for solving the puzzle attached in the screenshot)

[qu]aaevftmeimsckou

It will then store a file called 

[qu]aaevftmeimsckou.txt.

Here's the results of it running that:

teams
omits
ammos
steam
stick
stave
smoke
vitae
smite
items
meats

My dictionary is lacking words, it only has 81,536...

One thing to point out. Since Javascript does everything by reference, I have to clone the board for each level of recursion since they will mark letters as used and then future recursions will see them as used.  The clone board method clones the letter boxes and then correctly marks the currently used letters as used in the clone. This makes it correct.

The file uses a library I wrote for node.js to easily read / write files. You can download my [WordHero] solver here. You can fill in the missing fshelp methods with standard node file IO methods.


Enjoy!!

JsViews and JsRender Use Case...

I came across JsRender a few weeks ago, looking for an updated javascript template rendering system. I was in need for a side-project at work (yes, we have side projects sometimes, although honestly, I did most of it at home).  The basic gist of this side project is this: we have many clients, with many servers that we have to maintain, and each of those has different passwords. This would replace an Excel spreadsheet that sits on a shared drive, that when a password changes, we have to go in and update it, and it might be locked because someone else is viewing it.

The technological philosophy behind the creation of this application is this:  Users can log in, add clients, environments, credentials at will. The updates are seen almost immediately to other users logged in, through ajax polling. And an extensive history is kept so we can keep track of who updated what, and what it was before. Passwords are encrypted and viewable upon request.

Some definitions... environments are like, production, staging, dev. Credentials can be username / password for remote desktop access, database, the CMS admin, FTP, etc.

Also listed for each client is their subversion URL if they have one, the version of the development environment to use, which database and version, and what CMS and version they are using, if any.\

Here is a picture of it:


So here, the client is Delphic Sage (for our website, etc), none of these pieces of data are real.  There are four environments.

Data structure is as follows:

Client: Active, Name, Host (Rackspace, Self hosted, etc), Software list, comments, Environment list, History list
Software: version, DB reference to software (type (cms, devenv, database), name, versions list)
Environment: type (free text, usually production, staging, dev), url, credentials list
Credential: username, password, server or url (could be localhost, server name, url to admin login etc), comment

The whole thing is really cool. Maybe I'll put up a sample of it somewhere, but our app will be run internally of course.  I'll post another screenshot when the styles have been updated! The data structure I created in MongoDB is pretty much literally what you see on screen, and it taught me a lot about MongoDB. I also wrote a lot of helper methods to shorten the code a lot when dealing with MongoDB. The back end is my Node.js web server (what is running this website).  I can't think of anything else to add at the moment, so that means it might go into production very soon.

I'll make follow up posts with some code.

jQuery Events Expanded

Typically, when writing Javascript, you'll want to handle the click event for a certain element, or set of elements, so you can do this:

jQuery(".my-class").click(function(ev){ alert(jQuery(this).attr(id) + " was clicked"); });

What is less realized and utilized, is that you can use jQuery to add custom events to any Javascript object! This is pretty awesome. This is how it is done, in the most simple sense.

var MyObject = { makeCall: function(){ $.ajax("http://example.com/x", { method: "GET", success: this.completed }); }, completed: function(data, status, xhr){ $(this).trigger("complete", data); } };

In the most simple case, this can be used as follows:

$(MyObject).on("complete", function(e, data){ alert(JSON.stringify(data)); });

However, I would typically add convenience methods to the object, as follows:

var MyObject = { ... // other stuff. onComplete: function(fn){ $(this).on("complete", fn); } }

So now your code looks like this: MyObject.onComplete(function(e, data){ alert(JSON.stringify(data)); });

Of course, that is simply a global object. We would want to be able to allocate many instances of this, so then you change your code to this:

function MyObject(){ } MyObject.prototype.onComplete = function(fn) { $(this).on("complete", fn); }; MyObject.prototype.makeCall = function(){ $.ajax("http://example.com/x", { method: "GET", success: this.completed } ); }; MyObject.prototype.completed = function(data, status, xhr){ $(this).trigger("complete", data); };

Or any number of ways to skin that cat.

Where I used this was in a Javascript geolocator object. So, browsers now offer an ability to geolocate the user. This is more helpful on mobile browsers, but it's also available, albeit less accurately, on desktop browsers (although, to be fair, sometimes it's dead on!). The browser may not have this ability, however, so we should offer a fallback, like enter in a zip code or address, and allow Google's Maps API to geocode it. Like so:

;(function(window){ var GeoLocation = { locationRegex: /^[0-9\.\-,]+$/, parse: function(str){ var coords = { latitude: 0, longitude: 0 }; // parse "y,x", return { longitude: y, latitude: x } }, init: function(cookieName){ var self = this; this.cookieName = cookieName; this.on("located", function(e, coords){ self.updateLocation(coords); }); var stored = this.getStoredLocation(); if (this.checkLocation(stored)) $(self).trigger("located", stored); }, hasStoredLocation: function(){ // check cookie }, getStoredLocation: function(){ // get cookie as y,x call parse, return { longitude: y, latitude: x } }, clearStoredLocation: function(){ // erase cookie }, canGeocode: function(){ return navigator.geolocation != null && typeof (navigator.geolocation.getCurrentPosition) == "function"; }, getLocation: function(input){ var self = this; var defaultLocation = { longitude: 0, latitude: 0 }; if (typeof(input) == "string" && input != null && input.length > 0){ var geocoder = new google.maps.Geocoder(); geocoder.geocode({address: input}, function(result, status){ if (status == google.maps.GeocoderStatus.OK){ var res = result[0]; var loc = {latitude: res.geometry.location.lat(), longitude: res.geometry.location.lng()}; $(self).trigger("located", loc); } else $(self).trigger("failure", defaultLocation); }); } else if (self.canGeocode()){ navigator.geolocation.getCurrentPosition(function(position){ $(self).trigger("located", position.coords); }, function(error){ $(self).trigger("failure", defaultLocation); }); } else { $(self).trigger("failure", defaultLocation); } }, checkLocation: function(coords){ return !(coords.longitude == 0 && coords.latitude == 0); }, updateLocation: function(coords){ // store cookie }, // use: GeoLocation.on('located', function(coords){ alert(JSON.stringify(coords)); }); on: function(ev, cb){ $(this).on(ev, cb); } }; window.GeoLocation = GeoLocation; })(window);

So you can add a listener for any time that the user's location is determined, pretty much anywhere, thanks to jQuery, even without interacting with the DOM or DOM elements.

$(document).ready(function(){ GeoLocation.on("located", function(coords){ $("body").append($("<div>Located you at " + JSON.stringify(coords) + "</div>")); }); GeoLocation.on("failure", function(coords){ $("body").append($("<div>Couldn't locate you</div>")); }); GeoLocation.init("mysite-location-cookie"); GeoLocation.getLocation("Philadelphia, PA"); // a string parameter will cause it to invoke Google's Geocoding service. });

Javascript is a neat, capable little language. I hope this helps display that a little bit.

Another Example of my SyncArray

I refer you to my original post with my SyncArray code

function getSubdirs = function(path, callback){ fs.readdir(path, function(err, files){ var sync = new SyncArray(files); var subdirs = []; sync.forEach(function(file, index, array, finishedOne){ fs.stat(file, function(err, stats){ if (stats.isDirectory()){ subdirs.push(file); } finishedOne(); }); }, function(){ callback(subdirs); }); }); }

Messing Around in JS Object - Prevent Extensions

Lately I've been messing around with Javascript Object in Javascript 1.8.5 or greater. It's interesting but I've come across some peculiarities.

Object.preventExtensions tests

function d(){ this._test = 5; } //Object.preventExtensions(d.prototype); if (Object.isExtensible(d.prototype)){ Object.defineProperty(d.prototype, "test", { get: function(){ console.log("get called"); return this._test; }, enumerable: false, configurable: true } ); } var s = new d(); Object.preventExtensions(s); s.test = 6; console.log(s.test); s.jason = "jason"; console.log(s.jason);

Calling preventExtensions on d.prototype, the "test" property is never defined with the getter, so console.log(s.test) won't also log "get called". Object.preventExtensions(d.prototype) does not prevent extensions on instances of d. This one was weird to me, but they are two separate objects, so creating the property "jason" on "s" works unless I prevent extensions on "s". When preventExtensions is called on "s", console.log(s.test) prints 5 and console.log(s.jason) does not error out although it raises an error if I try to extend the prototype when it is not extensible.

Just some observations... This is the first in a series of posts on Object and its new methods in 1.8.5, I feel I need to know everything about it

Updated JS Combiner with JSMin!!

I updated my JS combiner functionality in the web server with JSMin! I found a Node.js JSMin implementation, added the line of code that minifies my combined file, and writes that out as the file to download. The one instance combined three big jQuery libraries that are used on almost every page, and it went from 37KB to 26KB. Before it was comparable in size to 37KB (probably identical) but it was three calls to the web server. This should limit the calls a ton.

Synchronized Array Access in Node.JS

I couldn't think of a good title for this one, but here's what I needed to accomplish: To loop over an array, but not moving onto the next element until finished with the current one. This is simple in synchronous, blocking code, but once you get to the world of Node.js and non-blocking calls going on everywhere, it becomes wildly more difficult. One could add the word "Semaphore" to this post and it wouldn't be too off the wall.

Take the following code for example:

var array = ["www.google.com", "www.yahoo.com", "www.microsoft.com", "www.jasontconnell.com", "givit.me"]; array.forEach(function(d, i){ http.get({ host: d, port: 80, path: "/" }, function(res){ console.log("index " + i + " got the response for " + d); }); });

Add in the appropriate "require" statements, run the code, and this is what I got the first time I ran it:

index = 0 - got response for www.google.com index = 3 - got response for givit.me index = 2 - got response for www.microsoft.com index = 4 - got response for www.jasontconnell.com index = 1 - got response for www.yahoo.com

That is not a predictable order! So how do we fix this? EventEmitter!! This took me a surprisingly small amount of time to figure out. Here's the code:

var http = require("http"); var EventEmitter = require("events").EventEmitter; var sys = require("sys"); function SyncArray(array){ this.array = array }; require("util").inherits(SyncArray, EventEmitter) SyncArray.prototype.forEach = function(callback, finishedCallback){ var self = this; this.on("nextElement", function(index, callback, finishedCallback){ self.next(++index, callback, finishedCallback); }); this.on("finished", function(){ }); self.next(0, callback, finishedCallback); } SyncArray.prototype.next = function(index, callback, finishedCallback){ var self = this; var obj = index < self.array.length ? self.array[index] : null; if (obj){ callback(obj, index, self.array, function(){ self.emit("nextElement", index, callback, finishedCallback); }); } else { finishedCallback(); self.emit("finished"); } } var array = ["www.google.com","www.yahoo.com", "www.microsoft.com", "givit.me", "www.jasontconnell.com"]; var sync = new SyncArray(array); sync.forEach(function(d, i, array, finishedOne){ http.get({ host: d, port: 80, path: "/" }, function(res){ console.log("index = " + i + " - got response from " + d ); finishedOne(); }); }, function(){ console.log("finished the sync array foreach loop"); });

And the output as we expected:

index = 0 - got response from www.google.com index = 1 - got response from www.yahoo.com index = 2 - got response from www.microsoft.com index = 3 - got response from givit.me index = 4 - got response from www.jasontconnell.com finished the sync array foreach loop

Feel free to update this with best practices, better code, better way to do it in Node.js (perhaps built in?), etc, in the comments. I'm really excited about this since holy F#@$ that's been frustrating!

Node.js Javascript Combining

The practice of combining and minifying JS files is one that should be done at all times. There's two ways to do this, one involves creating the combined file manually. The other involves fun and less future work.

I write my JS into many different files, breaking down functionality, but the client doesn't need to see that.

On my web server, I have a server side tag library that allows me to do stuff like include other files (so I can break up development into components), run "foreach" statements over arrays, conditional processing, and other stuff. I've added to this arsenal with a "combine" tag.

It's used like this:

<jsn:combine> /js/file1.js /js/file2.js /js/file3.js </jsn:combine>

These files get combined and added to the /js/combine/ folder, and the script tag gets written out in the response. This checks each time if one of the js files has been updated since the combined javascript file has been written.

There would be way too much code to spit out to show how all of the tags and the server works, so I'll just show the code that does the combine

var combineRegex = /(.*?\.js)\n/g; var rootdir = site.path + site.contentRoot; var combineFolder = "/js/combine/"; var file = combineFolder + jsnContext.localScope + ".js"; var writeTag = function(jsnContext, file){ var scriptTag = "<script type=\"text/javascript\" src=\"" + file + "\"</script>"; jsnContext.write(scriptTag); callback(jsnContext); } var combineStats = filesystem.fileStats(rootdir + file); var writeFile = combineStats == null; var altroot = null; if (site.config.isMobile && site.main != null){ altroot = site.path + site.main.contentRoot; } var paths = []; while ((match = combineRegex.exec(files)) != null){ var localPath = match[1].trim(); var fullPath = rootdir + localPath; var origStats = filesystem.fileStats(fullPath); var altStats = filesystem.fileStats(altroot+localPath); // add paths and determine if we should overwrite / create the combined file if (origStats != null){ paths.push(fullPath); writeFile = writeFile || combineStats.mtime < origStats.mtime; } else if (altroot != null && altStats != null){ paths.push(altroot+localPath); writeFile = writeFile || combineStats.mtime < altStats.mtime; } } writeTag(jsnContext, file); if (writeFile){ filesystem.ensureFolder(rootdir + combineFolder, function(success){ if (success){ filesystem.readFiles(paths, function(content){ filesystem.writeFile(rootdir+file, content, function(success){ }); }); } }); }

Some other stuff going on... my server has built in mobile site support. You can specify "this is the mobile site for this full site" and "for this mobile site, this is the main site", both running independent but they know of each other. I can have the file /js/mobile-only.js combined on the mobile site, where that file exists in the mobile site's content root, and I can have the file /js/main-site-only.js combined on mobile, where that file only exists on the main site.

Some nice to haves would be to also minify the files on the fly.

Javascript parseInt gotcha...

I was parsing an international date format, like this: 2011-08-04T11:23:21.345Z. After getting back December as the month for August, I was mildly perplexed. Here was the issue

From the Mozilla docs for parseInt: If the input string begins with "0", radix is eight (octal). This feature is non-standard, and some implementations deliberately do not support it (instead using the radix 10). For this reason always specify a radix when using parseInt.

Always specify a radix!!

Can you break it?

<script type="text/javascript">
function cleanseField(str){
str = str.replace(/<(/?)(b|i|u|em)>/ig,"_$1$2_").replace(/<.*?>/g,"").replace(/_(/?)(b|i|u|em)_/ig,"<$1$2>");
return str;
} function doit(){
var str = "<h3>Header</h3>Hello, my name is <eM>jason connell</Em>. <b>You</B> are awesome, like <i>italics</i><<scr"+"ipt>script type='text/javascript'>alert('sup');</sc"+"ript </scr"+"ipt>><u>underline</u>";

var spn = document.getElementById("test");
spn.innerHTML += "<h1>Original</h1>" + str;
spn.innerHTML += "<h1>Cleansed</h1>" + cleanseField(str);
}
</script>

<a href="javascript:void(0);" onclick="doit();">Doit</a>
<span id="test"></span>


Trying to cleanse html but keep certain elements for now. Tested in Chrome and IE 8, but is there a string that will still put out a valid script tag? It's very important.

If only there was a way in HTML that you can specify, "scripts are only valid inside this segment of the page". It's a shame that you could execute a script anywhere.