Saturday, June 10, 2006

Final project

Snippity

All in all I think it was probably too ambitious, especially having seen the other groups' presentations, but I think we pulled off a lot of what we had planned to do. It seems like I've been writing code nonstop for the past two weeks, but there you go.

I think if we ironed out the kinks we really could make this something publicly available and people would actually use it, and that's really cool. It's nice to make something potentially useful.

Professor Hollan made an interesting point about sharing and conversations, and I think with that in mind if I were to make this public I would re-engineer the comments so each item could have comments added by multiple users, rather than a single comment field that everyone can edit. The way we have it now was designed with the idea of collaboration and group editing, but the conversation aspect is perhaps more valuable--and everyone would still be able to edit the description field, I suppose.

This change would require an additional table in the database with the comment itself, the itemid that it goes with and the user that posted it. Threading might be nice too, in which case there would need to be comment ids too and a way to associate comments with each other...ugh. But that's later, if I decide to keep working on this.

Sunday, June 04, 2006

Adding a group to the database

Located at /php/addgroup.php. Mostly the same code as additem.php, so it works much the same.

Differences:

  • No url variable. You can send it, but it won't do anything.
  • No user variable. Instead, it's a comma-separated list called "members" in the format "members=member1,member2,member3" etc.
  • No usertypes variable. It too is a comma-separated list whose values may be "person" or "group". It can have a single item, in which case it will be applied to all items, or it must have the same number of items as members. If this is not the case, you'll get "var success = false; var errors = new Array ('Number of members and membertypes must be the same.');".


Note: some effort should probably be made somewhere to ensure that the creator is part of the members list.

Saturday, June 03, 2006

Adding an item to the database

Links, etc. can now be added to the database via /php/additem.php. It currently has no validation in it, so try to call it correctly.

Variables that may be sent to it:

user: the identification number of a user or group - optional, but if you send it then you must also send usertype. If you do not send these then it is assumed that you want it associated with the current user and the userid is taken out of the session variables and usertype is set to "person."
usertype: says whether the user is a person or a group. Valid values are "person" and "group".
title (optional)
description (optional)
comment (optional)
tags (optional): all tags to be associated with the item in a comma-separated list (e.g. tag1,tag2,tag3)
year (optional): the expiration year, must be four-digit (e.g. 2006)
month (optional): the expiration month, must be two-digit (e.g. 06)
day (optional): the expiration day, must be two-digit (e.g. 03)
Note: year, month, and day must all occur together or the expiration date will be put in the database as an empty string. The creation date is created automatically.
Media (optional): this isn't implemented yet. When it is it will be an uploaded file. I have no idea how I'm going to process this.

If the user is not logged in, additem.php returns "success=false" and "loginfailure=true". When the item is successfully entered into the database it returns "success=true". There is no other error checking, so there are no other points that might return something. (this should perhaps be changed...)

Friday, June 02, 2006

More Ajax!

The login, logout, and signup code can now be accessed by javascript. They're located at /php/login.php, /php/logout.php, and /php/signup.php.

Javascript code is returned from the php page as a string, via the responseText method on an xmlHTTPRequest. Since it's just a string at that point it must be evaluated via the javascript eval(string) function. This will create the variables, which then be used as any variables would.

Login.php will return two javascript variables: success, which can be true or false, and message, which will be either "You are now logged in." or "Bad username or password." If success=true, this means the user has been successfully logged in and the first message is given. Otherwise, the user has not been logged in and the second message is given.

Logout.php returns the same two variables as login.php, but the values should always be true and "You are now logged out." If something goes horribly wrong and the user is not logged out, it wouldn't get to the point of returning those variables anyway.

Signup.php returns the success variable as before, plus an array called "errors". The first entry in the array (index 0) corresponds to the first field in the form, the second to the second, etc. Each entry in the array contains an error message. If there is no error message in an array index, it will be a blank string (i.e. "").

A demonstration of how these things can be called can be found here:
login
logout
signup
Please note that these pages are only for demonstration of the ajax calls and how to turn the returned strings into useful javascript, not an actual suggestion of how things should look/work.

General javascript code to call a php page

see it working first

The php page that's being called returns a string. The javascript in this example code will pop up an alert containing that string.

There are four methods here that will call the testAjax function, which in turn will create an xmlhttprequest to get the response string from the php page, then pop it up: a submit box in a form with an onsubmit method, a button in a form, a button outside of a form with an onclick method, and a link with an onclick method. Note also the "return false" after every event call.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>Test Page</title>

<script>

function createXMLHttpRequest() {
//create the xmlhttprequest in various browsers
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) {}
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
try { return new XMLHttpRequest(); } catch(e) {}
alert("XMLHttpRequest not supported");
return null;
}

function testAjax () {
var req = createXMLHttpRequest();
req.open("post", "test.php", true); //request type, page it goes to, and asynchronous
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
//allows php to read variables submitted (below) as it would data submitted through form actions

req.onreadystatechange = function() { //event listener to detect if the php is done running
if (req.readyState != 4) { return; } //4 is done, 1, 2, and 3 mean it's incomplete
alert(req.responseText); //display the response in an alert
//note that it could also be sent to another function for further processing
};

req.send("");//send the request; this would contain POST variables, but none are needed here
//format for these is variable=value&variable=value etc.
}

</script>
</head>

<body onLoad="alert('loaded');">

<form name="testform" onsubmit="testAjax(); return false">
<input type="submit" value="Test Submit"><br>
<button>Test Button 1</button>
</form>
<button onClick="testAjax();">Test Button 2</button><br>
<a href="#" onClick="testAjax()">Link</a>

</body>
</html>

Wednesday, May 31, 2006

The limits of free hosting

It just occurred to me that keeping images in the database itself isn't gonna work too well if we've got a size limit on the database. Well, proof of concept, eh? Just enough space for testing.

I suppose we could just have the file name in the database, with the file itself stored elsewhere. This might actually be easier to process--no BLOBs. I haven't worked with those in php before, but they can be a bear in Java.

This would require reworking the database a bit, though. Worrying about this later. The next bit of php will be the item creation code, which won't have images at all in it just yet until I get everything else working.

php signup code

Signup page

This code is in desperate need of functions. Not worrying about that right now. This would make it more accessible as an API for the AJAX, but these pages aren't APIs yet, just test code to flesh out the basics.

Anyway, once the page has been submitted, the php checks to see that all fields were filled in, that the password confirmation matches the password, and that the email address contains at least one letter, an @ symbol, and at least one other letter (not very sophisticated, but this project isn't about form error checking, and anyway email address is only for forgotten passwords).

If everything checks out, the values are entered into the database and the login variables are created on the session ($_SESSION['logged_in'], $_SESSION['username'], and $_SESSION['userid']). Try creating an account, logging out, then logging in--it works together! *happy working code dance*

(ugly,ugly) source

Tuesday, May 30, 2006

php login code

Log in page

Use "test" for both the username and password.

The login code checks the login info against the database. If the username is in the database and the password is correct it logs you in, otherwise it prints "Bad username and password."
source

The logout code destroys the session. For some reason destroying the session doesn't prevent the current page from seeing session data, so to get the logged in/not logged in behavior to work correctly it had to be on a separate page. This is probably better, anyway, since it can just be called like this from anywhere.
source

Saturday, May 27, 2006

Documentation: Database Tables

I created an account for our team over at funpic.org, and a group email account since it wanted an email address. Also, our team is officially female, at least to the people over over at funpic.

The database is kinda sorta set up. Please note that I know next to nothing about efficient database design.

items table - the main table with all the bookmarked items in it.
Structure:
itemid - int(10) - UNSIGNED - Not null - Auto increment
url - varchar(255)
user - int(10) - UNSIGNED - Not null - Default: 0
usertype - enum('person', 'group') - Not null - Default: person
media - blob - BINARY
thumbnail - blob - BINARY
mediatype - varchar(10)
title - varchar(255)
description - text
comment - text
tags - text
creation - date - Not null - Default: 0000-00-00
expiration - date - Default: 0000-00-00


Most things should be self-explanatory, but some things should be explained:

Indices for the table are url, user, usertype, title, creation, expiration, mediatype. These are the things I suspect will be searched by most often, so this should speed things up if the database gets very large. Itemid is the primary key.

I figured it was ok for most of the things in the table to be null, since you shouldn't have to set all of them for everything--e.g. you shouldn't need to set an expiration date if you don't want something to expire. Things that can't be: itemid, so a specific item can be found again later, user and usertype, so the bookmark (or whatever we're calling these things?) can be associated with a person or group space (it's kinda useless if no one owns it, no?), and creation date, since there's no reason this couldn't be created automatically upon entry into the database.

Itemid is the primary key. Items will generally be selected by user, but to edit an item it will probably be easiest to use an identification number, rather than selecting by user and url or something--especially since a url may not necessarily be required for an entry(???).

User is a 10-digit identification number that can be associated with either a user or a group workspace. It's a fixed-length number, rather than a varchar name (e.g. username or group name) because 1)the internet tells me it will work faster this way; and 2)a group won't necessarily have a name(???). The number can be looked up in the users or groups table, depending on what usertype is--or the other way around of course; actually, that's the more probable case: someone requests something that belongs to them or that belongs to a group they have access to, their number or the group number is looked up, then a second query looks up in the items table where user = their number or the group number and usertype = person or group, depending.

Mediatype needs to change from varchar to an enum, with a list of acceptable file types. I'll figure this out when I start doing the php code to deal with those.

Description is a text entry, perhaps a clip from a website. Comment will be the user's comment on it. Or the user could just use one or the other for both.

Currently the tags go in a text entry. This means each tag needs to be separated from each other tag by a comma or some other delimeter. This may not be an acceptable solution, especially since text entries cannot be indexed--meaning very very slow searches. Then again, if all entries that someone has access to are pulled once and the tags are put in some other format to be accessed by javascript, this may work quite well. I really do need to learn more about relational databases.

users table - the table of user names and passwords. (Eeek, I'm gonna have to figure out sessions in php, aren't I?)
Structure:
userid - int(10) - UNSIGNED - Not null - Auto increment
username - varchar(25) - Not null
password - varchar(25) - Not null
email - varchar(50) - Not null


Username and email are indices, userid is the primary key. It seems kinda silly to index password, since it seems highly unlikely that I would search by password and not one of the other two columns.

Mostly the only reason email is there is so if people can get their passwords they can retrieve it. There could be fields for things like address, phone number, and whatever else that sites ask you when you sign up for something, but I don't think we actually care about any of those, do we?

There may eventually be other columns with various preferences, but since we haven't decided what those will be yet they aren't in there.

groups table - the table of groups, group descriptions, and who has access.
Structure:
groupid - int(10) - UNSIGNED - Not null - Auto increment
user - int(10) - UNSIGNED - Not null - Default: 0
usertype - enum('person', 'group') - Not null - Default: person
media - blob - BINARY
thumbnail - blob - BINARY
mediatype - varchar(10)
title - varchar(255)
description - text
comment - text
tags - text
creation - date - Not null - Default: 0000-00-00
expiration - date - Default: 0000-00-00


This table is pretty much the same as the items table, since one of the ideas is that someone should be able to treat a group they have access to the same way they would treat an individual item. Hence the media, tags, comments, etc. columns. The indices are the same also, with the exception of url, which is not in this table.

Groupid is also treated as an index, not a primary key, because each group will be in the table more than once. This allows each user with access to it to create their own personal tags, comments, etc. that aren't shared by the other members. When a group is created all users will have those fields set to whatever the group creator puts in them, but the other users can modify those thereafter. Theoretically there could also be comments, etc. visible to the entire group, which would be stored in a row where the group is owned by itself--i.e. the usertype would be "group" and the user would be the same as the groupid.

This brings up a second point: a group can be accessed by users, but also by other groups. So you could have two groups where all the members also have access to a third group workspace. I'm not really sure what this buys you--maybe subcommittee type stuff?--but it's pretty easy to implement and might be useful, so why not?



And that's the database, thus far.

Some final comments:

Group space versus individual space
Because of the way the items table is set up, there is no natural way for an item owned by a group to be linked to another part of an individual's workspace. Well, I guess tagging might do it, but I haven't figured out quite how. The more likely case is that there would be two entries in the database, one belonging to the group and another belonging to the user, with a checkbox or something in the interface that says to update the other copy. Then the php update function will be called multiple times, once for the one you're actually changing and again for the linked item. I don't yet know how to link between the two--tagging might come in here, too.

Multiple users and threading
More than one person can be working in a group workspace at once, even editing the same item. How do we maintain that item's integrity? Some sort of javascript refresh function will help, but if two people are editing the same item concurrently and hit submit several seconds apart, how do we keep from losing the changes created by one without ruining both?



Next stop, PHP!

Tuesday, May 23, 2006

Some sites I mentioned in the meeting yesterday

JavaScript Object-Oriented Programming Part 1
I hadn't used javascript constructors before, but they're pretty cool--objects make a lot of things much easier. Been working on some test code (which probably won't make it into the project) using objects just to try it out :)

JPSPAN
Examples of how to write code so that javascript and php can work together. This used to be part of a wiki, but that's gone now so there's not much explanation. Examples are still good, though.

Monday, May 15, 2006

The history object and AJAX

Sunday, May 14, 2006

Some server-side reference notes

W3Schools SQL tutorial
SQL data types
Connecting to a database
Querying the database

Using PHP to connect to a database:

require 'DB.php'; //uses the PEAR DB package
$db = DB::connect('[programtype]://[username]:[password]@[hostname]/[databasename]');
if(DB::isError($db)) { die("Can't connect: ".$db->getMessage()); } //error message

The things in the second line in brackets need to be replaced with the actual values. Note that there are no square brackets in the actual call, they're just there to mark off which bits need replacing.

[programtype] varies depending on what type of program your database server is running. Here is a list of possible values (blatently stolen out of Learning PHP5 page 117-118, but shh, don't tell anyone):

[programtype] valuedatabase program
dbasedBase
fbsqlFrontBase
ibaseInterBase
ifxInformix
msqlMiniSQL
mssqlMicrosoft SQL Server
mysqlMySQL (versions <= 4.0)
mysqliMySQL (versions >= 4.1.2)
oci8Oracle (versions 7,8,9)
odbcODBC
sqliteSQLite
sybaseSybase


[username] and [password] are pretty self explanitory.

The [hostname] depends on where your server is, so if it's on the same machine as the server you're connecting from you might use localhost, or if it's elsewhere you can use the IP address or domain name.

[databasename] is the name of the particular database you're trying to access. Since it is possible to have multiple databases on the same host, you have to specify which database exactly it is that you want to connect to. Every database must have a unique name.

The error message part is useful especially in testing, telling you if you've misstyped the password or are trying to connect to something that doesn't exist. I'm not sure I'd allow such an explicit error in a production-stage application, maybe just a general error that the database appears to be down, try again later rather than $db->getMessage(). When an error is encountered, no further php scripts are run; the program exits and prints an error message.

Sending SQL queries to the database:

function queryError ($error_object) {

//stuff you want to happen when an error occurs
//eg printing the error to the screen for debugging:
print "Query error: " . $error_object->getDebugInfo();
//or sending it to an error log (where visitors can't see it):
error_log($error_object->getDebugInfo());

}
$db->setErrorHandling(PEAR_ERROR_CALLBACK,'queryError');
$q = $db->query("[SQL query]");

[SQL query] must be replaced with any valid SQL statement.

setErrorHandling creates a default error behavior for every SQL query. isError can also be used like it was with the database connection, but it needs to be used for every query sent, so setErrorHandling is much more efficient if you want the same behavior for every failed SQL statement.

The second argument of setErrorHandling is a custom function that includes statements you want to be executed when an error occurs, e.g. printing an error message to the screen. The first causes that function to be called and then creates the standard php "die" behavior for ending all scripts when an error is encountered.

Tuesday, May 09, 2006

Hyperlinks! Whoah! (die, blogger templates, die)

So I think that having a personal blog, group blog, and group wiki is going a little overboard about this whole interactive internet thing (too many collaboration spaces = no collaboration at all???), but they're all linked in the sidebar over there now, anyway. You all should feel totally special that I did that so you can navigate between all our stuff, because blogger templates make me angry and want to hit things--namely the people that created such an apalling design for them. Rawr, say I. RAWR!

Sunday, April 30, 2006

Douglas Adams and the Internet

(This is a really long quotation, but it's all good, I promise!)
Nowadays, because of the plethora of one-to-many communication we have, if a plane crashes in India we may get terribly anxious about it but our anxiety doesn’t have any impact. We’re not very well able to distinguish between a terrible emergency that’s happened to somebody a world away and something that’s happened to someone round the corner. [...] We’ve all become twisted and disconnected and it’s not surprising that we feel very stressed and alienated in the world because the world impacts on us but we don’t impact the world. [...]

But the fourth [kind of communication], the many-to-many, we didn’t have at all before the coming of the Internet, which, of course, runs on fibre-optics. It’s communication between us that forms the fourth age of sand. Take what I said earlier about the world not reacting to us when we react to it; I remember the first moment, a few years ago, at which I began to take the Internet seriously. It was a very, very silly thing. There was a guy, a computer research student at Carnegie Mellon, who liked to drink Dr Pepper Light. There was a drinks machine a couple of storeys away from him, where he used to regularly go and get his Dr Pepper, but the machine was often out of stock, so he had quite a few wasted journeys. Eventually he figured out, ‘Hang on, there’s a chip in there and I’m on a computer and there’s a network running around the building, so why don’t I just put the drinks machine on the network, then I can poll it from my terminal whenever I want and tell if I’m going to have a wasted journey or not?’ So he connected the machine to the local network, but the local net was part of the Internet—so suddenly anyone in the world could see what was happening with this drinks machine. Now that may not be vital information but it turned out to be curiously fascinating; everyone started to know what was happening with the drinks machine. It began to develop, because in the chip in the machine didn’t just say, ‘The slot which has Dr Pepper Light is empty’ but had all sorts of information; it said, ‘There are 7 Cokes and 3 Diet Cokes, the temperature they are stored at is this and the last time they were loaded was that’. There was a lot of information in there, and there was one really fabulous piece of information: it turned out that if someone had put their 50 cents in and not pressed the button, i.e. if the machine was pregnant, then you could, from your computer terminal wherever you were in the world, log on to the drinks machine and drop that can! Somebody could be walking down the corridor when suddenly, ‘bang!’ — there was a Coca-Cola can! What caused that? — well obviously somebody 5,000 miles away! Now that was a very, very silly, but fascinating, story and what it said to me was that this was the first time that we could reach back into the world. It may not be terribly important that from 5,000 miles away you can reach into a University corridor and drop a Coca-Cola can but it’s the first shot in the war of bringing to us a whole new way of communicating. So that, I think, is the fourth age of sand.


From Is there an Artificial God?, a speech from Digital Biota 2, 1998

Sorry for the excessively long quotation, but I thought it was necessary to get his point across there. The speech discusses what he calls the four ages of sand: lenses for telescopes, looking outward; lenses for microscopes, looking inward; silicon for computers for computing things we never understood before; and fiber optics, for communication. Every one of those things significantly altered the way people think about their relationship to the world. (Well, not the fiber optics in themselves, as with the other things, but the idea behind them certainly.)

It's cliche by now to talk about the communication revolution of the internet, but the way he says it here...it becomes profound again, for me. The movement of passive acceptance of constant bambardment of media to talking back. Going from a receiver to both receiver and source.

The power of distribution is out of the hands of media corporations, printing presses, etc. Suddenly mass publishing goes from immensely difficult to almost trivial--what, if not that, am I doing here, and for free?! And in doing so the value, contents, purpose, etc. of the messages change.

Thursday, April 27, 2006

The Project (dun dun dun....)

We will be working on a temporary bookmark storage system. It will incorporate ideas from del.icio.us and Backpack, with more of an emphasis on personal use and personal organization.

The project will feature:

  • An Ajax interface, possibly including some sort of drag and drop elements

  • Some sort of backend, since we'll need to store stuff in a database--backend programming will be minimal, all of the display should be done with css and javascript

  • Some sort of organization abilities, perhaps with folders and/or tagging??


I've got some server experience with SQL, PHP, and Java/Tomcat, so we won't need to have someone pick up a whole new language (although I did pick up asp in about a week, so I could if necessary (and lost it shortly thereafter, so nevermind)). I've also got experience with Ajax, but so will everyone else soon, so whatever. We will be needing server space somewhere--I can test server stuff locally, but we're going to need something that everyone can access any time and doesn't depend on my (potentially moribund) computer. Funpic is an option if we can't get school computer space in which we can install a php or java server and a sequel server.

One interesting problem is how things should be organized. Ideas tossed out so far include a hierarchy or some sort of associative system, e.g. tagging. I really dislike the idea of a hierarchy because so often that just isn't the optimal way to categorize things--most things don't fall into a single, obvious branch of a rigid taxonomy. Of course, a tagging system in the server (to prevent multiple entries under different branches, etc.) does not preclude a hierarchical display browser-side, especially if one could also tag tags. And really, there's no reason we couldn't have several possible organizational views. Really this is all just brainstorm right now. I'd need a piece of paper and a pen to describe what I'm thinking any better.

Wednesday, April 26, 2006

Javascript + CSS + DOM = Good Times

Number slider game

It's a test file that ended up getting slightly out of hand. Think I can get away with using it to replace projects 2 and 3?

The code is pretty messy at the moment, really it should be broken up into at least 3 .js files, but it's easier to view source this way--in case anyone really cares enough to want to. Some of the functions are pretty unweildy, too, they might be cleaned up later. I should probably go back and comment it better, too. Meh.

Friday, April 21, 2006

Ubicomp!

Purse Won't Let You Forget Keys
I believe because people have seen how technology can make their everyday lives easier, they now want more traditional products updated to offer the same benefits

I suppose I should make some sort of comment on it, but I think that quote says it all really. Ubiquitous computing, hooray! If it were less ugly I'd buy one ;)

Speaking of online drawing thingies...

This thing is way too fun. Made in flash, not Ajax, but we'll forgive it for that. (Whee!)

Tuesday, April 18, 2006

Assorted thoughts from Minicon

This weekend some friends and I went to Minicon, in Minnesota. It's a sci-fi/fantasy convention with lots of interesting writers--and interesting non-writers, of course. Despite the lack of food and my being sick for a lot of the weekend, we had a really good time.

On the plane up to Minnesota I was listening to the little tones they have that mean things to the crew but are completely meaningless and pretty unobtrusive to everyone else. It seems like it's fairly recently that people really started getting into alternative interfaces that aren't just text on a screen, e.g. that clock with images around the outside from live video feeds from other places that we saw in 120 (or possibly 102c?) last year. But I realized that this is an alternative interface too--it conveys information via a sequence of tones that is clear for those in the know but inscrutable to anyone else. It's fairly limited in what it can convey, and for all I know it may only be one way, though it doesn't necessarily have to be. But for what it's used for it works very well, conveying the necessary information without being irritating to everyone else--and it's been around for quite some time. I just thought that was kind of interesting.

A second event that occured at Minicon is related to something Professor Hollan said in class today. Some background may be required first: Harlan Ellison, author of "I have no mouth but I must scream," among other things, was the special guest author for this year's conference. In addition to his works, he's well known as being very outspoken and opinionated, to the point of being a jerk, really. So Saturday evening we're standing around, and Amanda and Zack are on the phone calling people about dinner plans. Harlan comes up and yells at Amanda for being on the phone every time he sees her, takes Zack's phone from him and hangs it up, then rants at us about how much he hates cell phones for several minutes. His main objection seems to be that he feels like he's surrounded by crazy people walking around talking to themselves, and they should all be locked up. (At this point Zack responded that if they were all locked up together they'd have no need for phones anymore.)

Now I don't much care that everyone looks like they're talking to themselves, though I admit it can be disconcerting when you can't see the phone and someone seems to be looking straight at you and saying something, then when you respond they give you a look like you're the crazy person. But there are plenty of other reasons to hate cell phones, not the least of which being the interruptions they cause. For instance, restaurants and movie theatres, especially when the person with the phone insists on talking abnormally loudly. Or of course, my personal pet peeve is when I'm with someone and we're having a nice conversation, then they're phone rings and they're on the phone for the next 15 minutes, leaving me twiddling my thumbs. If I had a penny for every person I've seen using a cell phone to be rude....

This actually reminds me of an article I read about the Amish and technology a while back. It seems that the Amish are not unilaterally opposed to all technology, and indeed will allow things in, provided that it does not harm the coherence of the whole community. When asked about installing phones in homes, rather than out in a booth in the meadow, one man told the reporter, "What would that lead to? We don't want to be the kind of people who will interrupt a conversation at home to answer a telephone. It's not just how you use the technology that concerns us. We're also concerned about what kind of person you become when you use it." An interesting mindset, for sure.

Tuesday, April 11, 2006

Some css, javascript, and xml links

CSS Zen Garden - Some really beautiful layouts illustrating the power of CSS to totally change the character of a page

StrangeBanana - Randomly generated CSS layouts, good for helping you get ideas

Nifty Corners: rounded corners without images - How to give things in your page rounded corners using CSS alone

Modifying Styles - how to use javascript to modify your css files

cssQuery - a javascript method that lets you select html tags in the document using CSS selectors

Unobtrusive show/hide behaviour reloaded - using javascript vs. css to show and hide parts of your page (I'm not sure the caveats still apply, since the article is 2 years old, but it's worth looking at anyway)

String Matching and Replacing with JavaScript 1.2 - Very helpful for Javascript form validation, uses Perl regular expressions (which are explained within the page). The original page is gone now, but thank heavens for archive.org!

Javascript form validation - Doing it right - Suggestions on how to integrate javascript form validation into your web application in a user- and database-friendly way

Forms, Usability, and the W3C DOM - Using the html document object model to create forms that are more user-friendly

Very Dynamic Web Interfaces - loading xml files with javascript (plus some php)

Friday, April 07, 2006

Traces of Culture

Traces of Culture is an interactive art piece by Stephen Wilson of SFSU that compares the web to the ancient library at Alexandria and the encyclopaedia of the middle ages: all are attempts to compile knowledge into a single widely-accessible resource. However,

The existence of this worldwide compendium is not sufficient in itself. Its contents are mute and impotent without methods to search its fullness.


The piece is therefore an artistic exploration of keyword search.

I actually find the quotation above far more interesting than the project itself (I find the actual implementation kind of irritating): you can have all the information in the world, but if you can't access it then it's totally worthless. Actually, that's Google in a nutshell, come to think of it.

He also has some other interesting art projects, all very HCI related, that are worth checking out.