JSS – Nested CSS using Javascript

May 1st, 2009

Ever wanted nested stylesheets?

I have!

Now you can have them! If you code your stylesheets as JSON and parse them using JSS 0.1. You could have the following:

      JSS({
        'html': {
          'body': {
            background: '#fff',
 
            'div#header': {
              height: '100px',
              background: '#00f'
            },
 
            'div#footer': {
              height: '40px',
 
              'span#copyright': {
                color: '#0f0'
              },
              'span#testing': {
                color: 'black',
                background: '#eeccff'
              }
            }
          },
          width: '800px'
        }
      });

Turned into:

      html {
        width: 800px;
      }
 
      html body {
        background: #fff;
      }
 
      html body div#header {
        height: 100px;
        background: #00f;
      }
 
      html body div#footer {
        height: 40px;
      }
 
      html body div#footer span#copyright {
        color: #0f0;
      }
 
      html body div#footer span#testing {
        color: black;
        background: #eeccff;
      }

You can get it here or view the test page here.

jsDebug 0.1 – Dump javascript objects

April 30th, 2009

There have been many times I’ve wanted to debug an object in various browsers, and see why that particular key is null in IE6 or whatever, so I’ve made this small independent ‘Debug()’ function for use in all the major browser

It’s not dependent on any frameworks and gives a simple interface listing all information about objects required. Each call to Debug() adds a new table at the top of the panel showing the information retrieved from the pass variable.

It’s only a first draft and the depth feature doesn’t actually work as object depth yet, but rather as the number of internal objects to dump before not doing any more… Any recursion experts feel free to add this, but please share it :)

Not so pretty, functional though...

Not so pretty, functional though...

You can get it here or see it in action too. Oh it’s free, do what you want with it.

jQuery – Automatic Image Captions

April 22nd, 2009

Lots of RTEs allow you to add images and float them, but not many allow for simple captions to be wrapped around the images…

This script in conjunction with jQuery allows just that… Very simple and fairly unobtrusive.

If you wanted to add captions to all images (from their longdesc, title or alt attributes) within <div class=”content”/> you could do:

$('div.content').addCaptions();

Which produces something like this:

jQuery Add Captions - Screenshot (Like this!)

jQuery Add Captions - Screenshot (Like this!)

No styling is carried out by the script itself, so you’ll have to add in some extra classes, but in the zip file should be everything you need to get started (including jQuery 1.3.2 minified).

Download

Edit: Added to the work blog too.

Simple Inheritance on Javascript Objects

January 20th, 2009

I’ve been playing a lot with javascript lately and needed to extend an object, retaining all the existing methods but also adding more.

This simple script allows exactly that:

Object.prototype.implement = Function.prototype.implement = function(props) {
  for (var key in props) {
    this[key] = props[key];
  }
 
  return true;
}
 
Object.prototype.extend = Function.prototype.extend = function(props) {
  var obj = new this.constructor();
  obj.prototype = this.prototype;
  obj.implement(this);
 
  if (props) {
    obj.implement(props);
  }
 
  return obj;
}

It should be used similar to how you would extend a class in PHP i guess:

var Class = function() {
}
 
Class.prototype.test = function() {
  alert('test');
}
 
var Class2 = Class.extend();
 
Class2.prototype.test2 = function() {
  alert('test2');
}
 
var obj = new Class();
 
var obj2 = new Class2();
 
obj.test();
// alerts test
obj.test2();
// throws an exception
obj2.test();
// alerts test
obj2.test2();
// alerts test2

I know there are many frameworks that probably already do this better, but if you just need a simple object extension method, this should work.

jsInflections – Ruby style inflections for Javascript

January 14th, 2009

Small class, that handles inflections like ruby for javascript strings, eg:

alert('cow'.pluralize());  // alerts cows
alert('cows'.singularize()); // alerts cow

Pretty simple, all methods except constantize have been replicated.

This file is probably mostly the work of the rails team, so the same license applies to this, as rails itself.

Download (3.3KB)

Webkit (Safari) – Speed Dial bookmarklet

January 13th, 2009

Since chrome (well I know opera did it way back when… but anyway) the speed dial feature of a browser has become very popular and I thought that since bookmarklets are cool and webkit has a database engine, surely these ideas could all be combined, so I’ve built a simple speed dial page written totally in javascript with webkit’s SQL engine.

It’s not super pretty, surely has some bugs (if you load the bookmarklet from anything other than a new tab, you’ll have no favourites and also it can’t be your homepage, for some reason), and you need to sign up for a snapcasa.com account (it is free!) for the prettiness, but it’s mainly proof-of-concept.

speedDial bookmarklet for WebKit

speedDial bookmarklet for WebKit

To enjoy previews of the sites you’ve added, you’ll need to sign up for a free account at http://snapcasa.com/Register.aspx after which you will have to add your IP address (hopefully it’s static… sorry if not, but there are other solutions… http://www.webresourcesdepot.com/10-free-website-thumbnail-generation-services/)

You can download the package with a YUI compressed copy of the code and a fully expanded version below, or alternatively, you can copy this code, remembering to replace the SNAPCASA_CODE with your own code:

javascript:document.write('<html><head><title>Speed Dial</title></head><body><div id="body"></div></body></html>');window.speedDial={rows:3,cols:3,data:[""]};var body=document.getElementById("body");if(window.openDatabase){var database=window.openDatabase("SpeedDial","1.0","Speed Dial settings",200000);if(database){var loadSettings=function(){database.transaction(function(A){A.executeSql("SELECT rows, cols FROM SpeedDialSettings",[],function(C,B){for(var D=0;D<B.rows.length;++D){var E=B.rows.item(D);window.speedDial.rows=parseInt(E.rows);window.speedDial.cols=parseInt(E.cols)}},function(B,C){body.innerHTML=C.message;return})})};var loadData=function(){database.transaction(function(A){A.executeSql("SELECT * FROM SpeedDialSites",[],function(C,B){for(var D=0;D<B.rows.length;++D){var E=B.rows.item(D);window.speedDial.data[E.id]=E.url}},function(B,C){body.innerHTML=C.message;return})})};var changeSite=function(A){database.transaction(function(B){B.executeSql("SELECT * FROM SpeedDialSites WHERE id = ?",[A],function(D,C){if(C.rows.length==0){var E=checkURL(window.prompt("Enter the URL for cell "+A));if(E===false){return}if(E.length>0){D.executeSql("INSERT INTO SpeedDialSites (id, url) VALUES (?, ?)",[A,E],function(H,G){window.setTimeout(function(){render()},400)},function(G,H){alert(H.message)})}}else{if(C.rows.length==1){var F=C.rows.item(0);var E=checkURL(window.prompt("Enter the URL for cell "+A,F.url));if(E===false){return}if(E.length>0){D.executeSql("UPDATE SpeedDialSites SET id = ?, url = ?",[A,E],function(H,G){window.setTimeout(function(){render()},400)},function(G,H){alert(H.message)})}else{D.executeSql("DELETE FROM SpeedDialSites WHERE id = ?",[A],function(H,G){window.setTimeout(function(){render()},400)},function(G,H){alert(H.message)})}}else{alert("Too many rows!");return}}},function(C,D){alert("Error with SpeedDialSites table");return})})};var clearAll=function(){database.transaction(function(A){A.executeSql("DELETE FROM SpeedDialSites WHERE id > -1",[],function(C,B){},function(B,C){alert(C.message)})});window.setTimeout(function(){render()},400);return true};var changeSettings=function(){var A=parseInt(prompt("Please enter the number of rows you require"));var B=parseInt(prompt("Please enter the number of columns you require"));database.transaction(function(C){C.executeSql("UPDATE SpeedDialSettings SET rows = ?, cols = ? WHERE rows = ? AND cols = ?",[A,B,window.speedDial.rows,window.speedDial.cols],function(E,D){},function(D,E){alert(E.message)})});loadSettings();window.setTimeout(function(){render()},400)};var checkURL=function(A){if(A==null){return false}if(typeof A!="string"){return""}else{if(A.length>0){if(A.indexOf("http")==-1){return"http://"+A}else{return A}}else{return""}}};database.transaction(function(A){A.executeSql("SELECT * FROM SpeedDialSettings",[],function(C,B){if(B.rows.length==0){C.executeSql("INSERT INTO SpeedDialSettings (rows,cols) VALUES (?, ?)",[3,3])}else{}},function(B,C){B.executeSql("CREATE TABLE SpeedDialSettings (rows REAL, cols REAL)",[],function(E,D){E.executeSql("INSERT INTO SpeedDialSettings (rows,cols) VALUES (?, ?)",[3,3])})})});database.transaction(function(A){A.executeSql("SELECT COUNT(*) FROM SpeedDialSites",[],function(C,B){},function(B,C){B.executeSql("CREATE TABLE SpeedDialSites (id REAL UNIQUE, url TEXT)"),[],function(E,D){}})});var render=function(){loadSettings();loadData();body.innerHTML="";var G=document.createElement("table");G.cellSpacing="10px";G.style.width="90%";G.style.height="90%";G.style.marginTop="5%";G.style.marginLeft="5%";body.appendChild(G);for(var B=1;B<=window.speedDial.rows;B++){var I=document.createElement("tr");G.appendChild(I);for(var A=1;A<=window.speedDial.cols;A++){var C=(((B-1)*window.speedDial.cols)+A);var F=document.createElement("td");F.style.color="#ccc";F.style.border="8px solid #ccc";F.style.textAlign="center";F.style.fontFamily="Arial";F.style.width=parseInt(100/window.speedDial.cols)+"%";F.style.height=parseInt(100/window.speedDial.rows)+"%";F.num=C;F.onclick=function(){if(this.innerHTML==this.num||!this.url){changeSite(this.num)}else{if(event.altKey){changeSite(this.num)}else{window.location=this.url}}};F.onmouseover=function(){this.style.color="#999";this.style.border="8px solid #999"};F.onmouseout=function(){this.style.color="#ccc";this.style.border="8px solid #ccc"};if(typeof window.speedDial.data[C]=="undefined"){F.style.color="#ccc";F.style.fontSize="100px";F.innerHTML=C}else{F.url=window.speedDial.data[C];F.style.fontSize="15px";F.innerHTML='<img src="http://snapcasa.com/get.aspx?code=SNAPCASA_CODE&size=l&url='+F.url+'" alt=""/>'}I.appendChild(F)}}var D=document.createElement("a");D.href="#";D.onclick=function(){clearAll();return false};D.appendChild(document.createTextNode("Clear"));var E=document.createElement("a");E.href="#";E.onclick=function(){changeSettings();return false};E.appendChild(document.createTextNode("Settings"));D.style.color="#ccc";D.style.textDecoration="none";E.style.color="#ccc";E.style.textDecoration="none";var H=document.createElement("p");H.style.fontFamily="Arial";H.style.color="#ccc";H.appendChild(D);H.appendChild(document.createTextNode(" - "));H.appendChild(E);body.appendChild(H)};loadSettings();loadData();window.setTimeout(function(){render()},100)}else{body.innerHTML="Error opening database"}}else{body.innerHTML="Error accessing database"};

and paste in directly!

Download (3.2KB)

As ever, this snippet is under the Creative Commons ShareAlike Attribution license.

php-log: Process apache log files with PHP

January 12th, 2009

I’ve recently had to quickly parse an Apache log file, to get basic usage statistics for a site over a month and wanted the ability to quickly process any general logs and store them in a MySQL table, so I’ve made a small package class.log.

Included in the package are:

  • class.log.php (the main class)
  • class.log.processor.php (an interface for a log processor, very basic!!)
  • class.log.output.php (a simple extension of the processor (outputs <p> tags with <span>s)
  • class.log.mysql.php (a simple mysql importer of the processed data)
  • parse.php (a simple implementation, bringing all the classes together)

The class is designed to use one line at a time from the log retrieved, and the regular expression specified in class.log.php can be modified to parse different types of logs as long as the matches array is also updated.

I’ve only used this for apache logs currently, which it managed quite well, I’m not sure if I’d use this script in an automated script, but I’ll leave that for you to decide.

As other scripts, this class is available under the Creative Commons Share Alike Attribution license.

Edit: Minor update, made class more generic and added more comments.

Download (3.7kB)

Conway’s Game of Life

November 18th, 2008

So, thanks to xkcd I learnt about something cool today that’s been around for ages (wish I’d studied more maths….).

All the sites I found for playing with the simulation had Java applets on them, so I wanted to make a javascript one, I know it’s not a true implementation, because it goes a bit mental at the edges… but it was interesting anyway…

It’s here anyway if anyone wants to play… The timings might be a bit of a problem if you create a huge grid with small squares… so be prepared for Internet Exploder to give you some memory leak issues…

http://www.dom111.co.uk/gameOfLife.html

mod-framework: PHP, light and easy

November 13th, 2008

I know there’s already infinite PHP framework out there, trying to be rails; and most of them are doing it really well, I just feel that none of them completely embrace the simplicity of convention over configuration, so I’m trying to build one that ticks all the boxes.

It’s pretty simple so far, and is only a few hundred KB, but I think it’s got some cool features, and maybe even potential.

Like the other stuff it’s under a Creative-Commons SA license and can be found at:

http://mod-framework.googlecode.com/.

Any opinions, suggestions, contributions would be gratefully received.

Current functionality:

Model-View-Controller system
MySQL support (using a modified version of the DB class from earlier)
script/server implementation in PHP
Helper association, so if you create a PageHelper class for your Pages controller all the functions will automatically be made ‘global’ (accessible view functionname() instead of Helper::functionname())
Includes mootools in the htdocs folder

The DB doesn’t work quite how I would have imagined it to (well, with PHP 5.3 it might… but I haven’t got it yet…) so currently any models are added to $GLOBALS[] so that for a Page model, $GLOBALS['Page']->find_by_name(’dom’), etc would work.

There’s probably some other stuff in there too…

Advent QC430 (QRC430) Windows XP Drivers

October 19th, 2008

Just spent hours trying to set up Windows XP on an Advent QC430 (QRC430) which had Vista on. There doesn’t seem to be a pack of drivers already for it so I thought that I’d combine all the drivers I found into one zip file for anyone else suffering the same misfortune, to save time hunting through forums and experimenting with trial and error.

Contains all the files you should need (display, wireless, touchpad, audio, etc).

Please let me know if there are any missing files, but I’ve just used all these to set up this laptop so they should all be there.

My first starting point was:

http://www.uktsupport.co.uk/advent/laptop/qc430.htm

which contained most of the files that were needed, although the display and wireless drivers failed.

File:

http://rapidshare.com/files/155476616/Advent_QC430.zip.html