/* Thank Simon Willison for addLoadEvent(func): See: http://simonwillison.net/2004/May/26/addLoadEvent/ */ function addLoadEvent(func) { var oldonload = window.onload; if (typeof window.onload != 'function') { window.onload = func; } else { window.onload = function() { if (oldonload) { oldonload(); } func(); } } } /* This function is like many others out there... I need to do more work and create a centralised library. I don't like the way Prototype does it, so here's my NodeFactory. Must add, a friend gave me a hand fixing it; I was using a series of tuples in an array, not dictionaries. */ function NodeFactory(dict, dd, doc) { var output; var i; if (typeof dict === 'string') { output = doc.createTextNode(dict); } else if (typeof dict === 'object') { output = doc.createElement(dict.name); if (dict.attribute) { for (i in dict.attribute) { if (dict.attribute.hasOwnProperty(i)) { output.setAttribute(i, dict.attribute[i]); } } } if (dict.children) { for (i = 0; i < dict.children.length; i++) { output.appendChild(this.NodeFactory(dict.children[i], dd, doc)); } } if (dict.id) { dd[dict.id] = output; } } return output; } /* This is a REALLY ugly sort of hack. */ function GenXFN(name) { /* If it toggles 'me' */ if(name == "me") { /* and 'me' is checked */ if(XFNDD['me'].checked == 1) { /* clear everything */ for(i in XFNDD) { XFNDD[i].checked = 0; } /* re-check 'me' - faster than an if in the for */ XFNDD['me'].checked = 1; } } else { /* otherwise if there is a name value set clear 'me' */ if(name) { XFNDD['me'].checked = 0; } } XFN_STRING = "" for(i in XFNDD) { if(XFNDD[i].checked == 1) { XFN_STRING += i + " " } } /* This goes through every value in the order it was added then appends it. To modify the order you move the NodeFactory call order (found near the bottom of the DrawXFN function). It then spits out everything except the last space. */ XFN_REL.value = XFN_STRING.substring(0,(XFN_STRING.length - 1)); } /* Spawns 'li' items to save some space. */ function Spawn(name, value, label, type) { litem = {'name':'li', 'children': [ {'name':'label', 'children': [ {'name':'input', 'id': value, 'attribute': { 'name': name, 'class':'radiolist inline', 'type': type, 'value': value, 'onclick':'GenXFN(this.value);' }, 'children': [ ]}, label, ]} ]} return litem; } function DrawXFN() { /* Single Entities in a Django-Admin Line are fine as they're not too big */ node_me = { 'name': 'div', 'attribute': { 'class': 'form-row xfn_me' }, 'children': [ {'name':'div', 'children': [ {'name':'label', 'children': ['My Site:']}, {'name':'input', 'id':'me', 'attribute': {'id': 'xfn_me', 'type':'checkbox', 'name':'me', 'onclick':'GenXFN(this.name);'}} ] } ] } node_met = { 'name': 'div', 'attribute': { 'class': 'form-row xfn_physical' }, 'children': [ {'name':'div', 'children': [ {'name':'label', 'children': ['Have Met:']}, {'name':'input', 'id':'met', 'attribute': {'id': 'xfn_physical', 'type':'checkbox', 'name':'met', 'onclick':'GenXFN(this.name);'}} ] } ] } /* These ones use space like nobody's business. Spawn was created to deal with population/space constraints. */ node_friendship = { 'name':'div', 'attribute': { 'class': 'form-row xfn_friendship' }, 'children': [ {'name':'label', 'children': ['Friendship']}, {'name':'ul', 'attribute': {'id':'xfn_friendship','class':'radiolist inline',}, 'children': [ Spawn('xfn_friendship', 'contact', ' Contact', 'radio'), Spawn('xfn_friendship', 'acquaintance', ' Acquaintance', 'radio'), Spawn('xfn_friendship', 'friend', ' Friend', 'radio'), Spawn('xfn_friendship', '', ' None', 'radio'), ] } ] } node_professional = { 'name':'div', 'attribute': { 'class': 'form-row xfn_professional' }, 'children': [ {'name':'label', 'children': ['Professional']}, {'name':'ul', 'attribute': {'id':'xfn_professional','class':'radiolist inline',}, 'children': [ Spawn('xfn_professional','co-worker', ' Co-Worker', 'checkbox'), Spawn('xfn_professional','colleague', ' Colleague', 'checkbox'), ] } ] } node_geographical = { 'name':'div', 'attribute': { 'class': 'form-row xfn_geographical' }, 'children': [ {'name':'label', 'children': ['Geographical']}, {'name':'ul', 'attribute': {'id':'xfn_geographical','class':'radiolist inline',}, 'children': [ Spawn('xfn_geographical','co-resident', ' Co-Resident', 'radio'), Spawn('xfn_geographical','neighbor', 'Neighbour', 'radio'), Spawn('xfn_geographical','', ' None', 'radio'), ] } ] } node_family = { 'name':'div', 'attribute': { 'class': 'form-row xfn_family' }, 'children': [ {'name':'label', 'children': ['Family']}, {'name':'ul', 'attribute': {'id':'xfn_family','class':'radiolist inline',}, 'children': [ Spawn('xfn_family','child', ' Child', 'radio'), Spawn('xfn_family','parent', ' Parent', 'radio'), Spawn('xfn_family','sibling', ' Sibling', 'radio'), Spawn('xfn_family','spouse', ' Spouse', 'radio'), Spawn('xfn_family','kin', ' Kin', 'radio'), Spawn('xfn_family','', ' None', 'radio'), ] } ] } node_romantic = { 'name':'div', 'attribute': { 'class': 'form-row xfn_romantic' }, 'children': [ {'name':'label', 'children': ['Romantic']}, {'name':'ul', 'attribute': {'id':'xfn_romantic','class':'radiolist inline',}, 'children': [ Spawn('xfn_romantic','muse', ' Muse', 'checkbox'), Spawn('xfn_romantic','crush', ' Crush', 'checkbox'), Spawn('xfn_romantic','date', ' Date', 'checkbox'), Spawn('xfn_romantic','sweetheart', ' Sweetheart', 'checkbox'), ] } ] } /* Could probably wrap this in a function to save some space */ XFN_DIV.appendChild(NodeFactory(node_me, XFNDD, document)) XFN_DIV.appendChild(NodeFactory(node_friendship, XFNDD, document)) XFN_DIV.appendChild(NodeFactory(node_met, XFNDD, document)) XFN_DIV.appendChild(NodeFactory(node_professional, XFNDD, document)) XFN_DIV.appendChild(NodeFactory(node_geographical, XFNDD, document)) XFN_DIV.appendChild(NodeFactory(node_family, XFNDD, document)) XFN_DIV.appendChild(NodeFactory(node_romantic, XFNDD, document)) /* Load the Values from the String before the user can mess with it. */ PreloadXFN(XFN_REL); } function PreloadXFN(form_value) { val = form_value.value; values = val.split(" "); for(i in values) { XFNDD[values[i]].checked = 1; } GenXFN(); } /* The entire process is hinged on this start up. */ addLoadEvent(function() { XFNDD = {}; XFN = {}; XFN_DIV = document.getElementsByTagName('fieldset')[2]; XFN_REL = document.getElementById('id_rel'); /* You can also mask either with .style.visibility = "hidden"; or .style.display = "none"; I suggest the latter, but both work fine. Personally I don't hide it, because I have form validation too and any click will change it. OPTIONALLY: Set onkeypress to check it. I didn't bother in this code. */ DrawXFN(); });