commit 872acdbc01476bca4f840e4dd478c3031075c784 Author: Némunaire Date: Sat Jul 30 00:14:52 2011 +0200 First commit, current version 0.2 diff --git a/.onyx b/.onyx new file mode 100644 index 0000000..c02a158 --- /dev/null +++ b/.onyx @@ -0,0 +1 @@ +./onyx2/load.php \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..fc740d3 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + pa4home + + + + + + com.aptana.ide.core.unifiedBuilder + + + + + + com.aptana.projects.webnature + + diff --git a/ajax.php b/ajax.php new file mode 100644 index 0000000..2368273 --- /dev/null +++ b/ajax.php @@ -0,0 +1,210 @@ + time(), "statut" => !empty($SESS->values["connecte"])); + +if ($json["statut"]) + $json["username"] = $SESS->values["username"]; + +//Création du fichier XML +$xml = new DOMDocument('1.0', 'UTF-8'); +$xml->formatOutput = true; +$xml_root = $xml->createElement("root"); + +$demande = gpc('d'); +$value = intval(gpc('i')); +if ($demande == "connecte") +{ + $nom = strtolower(gpc("name", "post")); + $mdp = hash("sha512", $nom.'♂♫↨'.gpc("mdp", "post")); + + $bdd = new BDD(); + $bdd->escape($nom); + $bdd->query("UPDATE users SET last_ip = '".$_SERVER["REMOTE_ADDR"]."', last_visite = ".time()." WHERE pseudo = '$nom' AND password = '$mdp';"); + $affected = $bdd->affected(); + if ($affected) + $user = $bdd->unique_query("SELECT * FROM users WHERE pseudo = '$nom' AND password = '$mdp';"); + $bdd->deconnexion(); + + if ($affected != 0) + { + $json["statut"] = 1; + $SESS->values["connecte"] = true; + $SESS->values["username"] = $nom; + $SESS->values["id_user"] = $user["id"]; + $SESS->put(); + } + else + { + $json["statut"] = 0; + $SESS->values["connecte"] = false; + $SESS->values["username"] = ""; + $SESS->values["id_user"] = 0; + $SESS->put(); + } +} +elseif ($demande == "logout") +{ + $SESS->values["connecte"] = false; + $SESS->values["username"] = ""; + $SESS->close(); +} +elseif ($demande == "accueil") +{ + $dir = opendir(APPSDIR); + while (($app = readdir($dir)) !== false) + { + if (is_dir(APPSDIR.$app) && is_file(APPSDIR.$app.'/property.xml')) + { + $applicationXML = new DOMDocument(); + $applicationXML->load(APPSDIR.$app.'/property.xml'); + + if ($applicationXML->documentElement->getAttribute('active') && $applicationXML->getElementsByTagName('application')) + { + //Vérification de sécurités + if (!acces_application($app, $applicationXML)) + continue; + + $xml_appli = $xml->createElement("application"); + $xml_appli->appendChild($xml->createElement("dir", $app)); + foreach($applicationXML->getElementsByTagName('property') as $property) + { + $xml_appli->appendChild($xml->createElement($property->getAttribute('value'), $property->textContent)); + } + $xml_root->appendChild($xml_appli); + } + } + } + closedir($dir); +} +elseif ($demande == "property" && $app = gpc('a')) +{ + if (empty($app) || ereg('/', $app) || !is_file(APPSDIR.$app.'/property.xml')) + send404($xml_root); + else + { + $appXML = new DOMDocument(); + $appXML->load(APPSDIR.$app.'/property.xml'); + + if ($appXML->documentElement->getAttribute('active') && $appXML->getElementsByTagName('application')) + { + //Vérification de sécurités + if (!acces_application($app, $appXML)) + continue; + + $xml_appli = $xml->createElement("property"); + foreach($appXML->getElementsByTagName('property') as $property) + { + $xml_appli->appendChild($xml->createElement($property->getAttribute('value'), $property->textContent)); + } + $xml_appli->appendChild($xml->createElement("dir", $app)); + $xml_root->appendChild($xml_appli); + } + } +} +elseif ($demande == "display" && $app = gpc('a')) +{ + if (empty($app) || ereg('/', $app) || !is_file(APPSDIR.$app.'/property.xml')) + send404($xml_root); + else + { + $appXML = new DOMDocument(); + $appXML->load(APPSDIR.$app.'/property.xml'); + + if ($appXML->documentElement->getAttribute('active') && $appXML->getElementsByTagName('application')) + { + //Vérification de sécurités + if (!acces_application($app, $appXML)) + continue; + + require(APPSDIR.$app.'/main.php'); + + $xml_root->appendChild($xml->createElement("dir", $app)); + + $xml_appli = $xml->createElement("display"); + foreach($appXML->getElementsByTagName('display') as $contenu) + { + if ($contenu->getAttribute('value') == "css") + { + $xml_css = $xml->createElement($contenu->getAttribute('value'), $contenu->textContent); + if ($contenu->getAttribute('media')) + $xml_css->setAttribute("media", $contenu->getAttribute('media')); + $xml_appli->appendChild($xml_css); + } + else + $xml_appli->appendChild($xml->createElement($contenu->getAttribute('value'), $contenu->textContent)); + } + $xml_root->appendChild($xml_appli); + + $xml_appli = $xml->createElement("property"); + foreach($appXML->getElementsByTagName('property') as $property) + { + $xml_appli->appendChild($xml->createElement($property->getAttribute('value'), $property->textContent)); + } + + if ($appXML->getElementsByTagName('menu')) + { + $menu = array(); + foreach($appXML->getElementsByTagName('menu') as $item) + $menu[] = array("text" => $item->getAttribute('text'), "eventClick" => $item->getAttribute('eventClick')); + + $xml_appli->appendChild($xml->createElement("menu", json_encode($menu))); + } + $xml_root->appendChild($xml_appli); + } + } +} +elseif ($demande == "action" && $app = gpc('a')) +{ + if (empty($app) || ereg('/', $app) || !is_file(APPSDIR.$app.'/property.xml')) + send404($xml_root); + else + { + $appXML = new DOMDocument(); + $appXML->load(APPSDIR.$app.'/property.xml'); + + if ($appXML->documentElement->getAttribute('active') && $appXML->getElementsByTagName('application')) + require(APPSDIR.$app.'/main.php'); + } +} +elseif ($demande == "page" && $page = gpc('p')) +{ + if (empty($page) || ereg('/', $page) || !is_file(PAGESDIR.$page.'.xml')) + send404($xml_root); + else + { + $pageXML = new DOMDocument(); + $pageXML->load(PAGESDIR.$page.'.xml'); + + if ($pageXML->documentElement->getAttribute('active') && $pageXML->getElementsByTagName('page')) + { + //Vérification de sécurité + if (!acces_application($page, $pageXML)) + send403($xml_root); + else + { + foreach($pageXML->getElementsByTagName('display') as $contenu) + { + $xml_root->appendChild($xml->createElement($contenu->getAttribute('value'), $contenu->textContent)); + } + } + } + } +} + +header("X-JSON: ".json_encode($json)); +$sortie = ob_get_contents(); +ob_end_clean(); +if (!empty($sortie)) + $xml_root->appendChild($xml->createElement("sortie", $sortie)); +$xml->appendChild($xml_root); +print $xml->saveXML(); +?> \ No newline at end of file diff --git a/applications/GSM/app.js b/applications/GSM/app.js new file mode 100644 index 0000000..5031b9c --- /dev/null +++ b/applications/GSM/app.js @@ -0,0 +1,1072 @@ +var GSM_origin_liste = false; +var GSM_liste = false; +var GSM_liste_CDA = false; //CDs année +var GSM_liste_CDC = false; //CDs chanteur +var GSM_liste_CDD = false; //CDs décénies +var GSM_lastSort = -1; +var GSM_delay = null; +var nbParPage = 50; + +//On charge la liste des porte-clés +function GSM_loadList() +{ + GSM_origin_liste = false; + GSM_liste = false; + GSM_liste_CDA = false; + GSM_liste_CDC = false; + GSM_liste_CDD = false; + GSM_lastSort = -1; + $('nbpc').innerHTML = 'Chargement en cours ...'; + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "action", a: "GSM", p: "liste"}, + onSuccess: GSM_parseList, + onFailure: function() { printEtat(3); } + } + ); +} +function GSM_loadSelectedList() +{ + //TODO: ne charger que les listes dont l'état est false + GSM_loadList(); +} +GSM_loadList(); + +//Une fois la liste reçue, on la parse +function GSM_parseList(transport, json) +{ + $('nbpc').innerHTML = json.nombre; + + var liste = transport.responseXML.documentElement.getElementsByTagName("liste")[0].getElementsByTagName("chanson"); + GSM_origin_liste = new Array(); + + for (var i = 0; i < liste.length; i++) + { + var elt = liste[i]; + GSM_origin_liste.push([elt.getAttribute("id"), elt.getAttribute("titre"), elt.getAttribute("chanteur"), elt.getAttribute("CD_annee"), elt.getAttribute("CD_interprete"), elt.getAttribute("CD_decenie")]); + } + + var liste = transport.responseXML.documentElement.getElementsByTagName("liste")[0].getElementsByTagName("cdannee"); + GSM_liste_CDA = new Array(); + for (var i = 0; i < liste.length; i++) + { + var elt = liste[i]; + GSM_liste_CDA[elt.getAttribute("id")] = elt.getAttribute("nom"); + } + + var liste = transport.responseXML.documentElement.getElementsByTagName("liste")[0].getElementsByTagName("cdchant"); + GSM_liste_CDC = new Array(); + for (var i = 0; i < liste.length; i++) + { + var elt = liste[i]; + GSM_liste_CDC[elt.getAttribute("id")] = elt.getAttribute("nom"); + } + + var liste = transport.responseXML.documentElement.getElementsByTagName("liste")[0].getElementsByTagName("cddece"); + GSM_liste_CDD = new Array(); + for (var i = 0; i < liste.length; i++) + { + var elt = liste[i]; + GSM_liste_CDD[elt.getAttribute("id")] = elt.getAttribute("nom"); + } +} + +function GSM_add() +{ + window.scrollTo(0,0); + $('contenu').innerHTML = ""; + titre = document.createElement("h2"); + titre.innerHTML = "Ajout d'un album à la base de données"; + $('contenu').appendChild(titre); + + GSM_addAlbum(); +} + +function GSM_edit() +{ + window.scrollTo(0,0); + $('contenu').innerHTML = ""; + titre = document.createElement("h2"); + titre.innerHTML = "Liste des albums"; + $('contenu').appendChild(titre); + + GSM_viewliste(0, 0, 0); +} + +function GSM_listAlbums() +{ + window.scrollTo(0,0); + $('contenu').innerHTML = ""; + titre = document.createElement("h2"); + titre.innerHTML = "Liste des albums"; + $('contenu').appendChild(titre); + + GSM_viewalbums(false); +} + +function GSM_listTitres() +{ + window.scrollTo(0,0); + $('contenu').innerHTML = ""; + titre = document.createElement("h2"); + titre.innerHTML = "Liste des titres"; + $('contenu').appendChild(titre); + + GSM_liste = false; + + GSM_viewliste(0, 0, 0); +} + +function GSM_addAlbum() +{ + var formulaire = document.createElement("form"); + formulaire.id = "addAlbms"; + formulaire.onsubmit = function() { newAlbum(); return false; } + var inpt = document.createElement("input"); + inpt.type = "radio"; + inpt.name = "cd"; + inpt.id = "cda"; + inpt.value = "1"; + inpt.onclick = function() { GSM_addAlbum_chColor(1); }; + formulaire.appendChild(inpt); + var lbl = document.createElement("label"); + lbl.htmlFor = "cda"; + lbl.innerHTML = "Ajouter un album d'année"; + formulaire.appendChild(lbl); + formulaire.appendChild(document.createElement("br")); + var inpt = document.createElement("input"); + inpt.type = "radio"; + inpt.name = "cd"; + inpt.id = "cdc"; + inpt.value = "1"; + inpt.onclick = function() { GSM_addAlbum_chColor(2); }; + formulaire.appendChild(inpt); + var lbl = document.createElement("label"); + lbl.htmlFor = "cdc"; + lbl.innerHTML = "Ajouter un album d'un interprête"; + formulaire.appendChild(lbl); + formulaire.appendChild(document.createElement("br")); + var inpt = document.createElement("input"); + inpt.type = "radio"; + inpt.name = "cd"; + inpt.id = "cdd"; + inpt.value = "1"; + inpt.onclick = function() { GSM_addAlbum_chColor(3); }; + formulaire.appendChild(inpt); + var lbl = document.createElement("label"); + lbl.htmlFor = "cdd"; + lbl.innerHTML = "Ajouter d'une compilation"; + formulaire.appendChild(lbl); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(document.createElement("br")); + var cntr = document.createElement("div"); + var lbl = document.createElement("label"); + lbl.htmlFor = "nom"; + lbl.innerHTML = "Nom :"; + cntr.appendChild(lbl); + var inpt = document.createElement("input"); + inpt.type = "text"; + inpt.name = "nom"; + inpt.id = "nom"; + cntr.appendChild(inpt); + cntr.appendChild(document.createElement("br")); + var lbl = document.createElement("label"); + lbl.htmlFor = "color"; + lbl.innerHTML = "Couleur :"; + cntr.appendChild(lbl); + var inpt = document.createElement("input"); + inpt.type = "color"; + inpt.name = "color"; + inpt.id = "color"; + inpt.onchange = function() { $("testColor").style.backgroundColor = $('color').value; }; + cntr.appendChild(inpt); + var test = document.createElement("div"); + test.id = "testColor"; + cntr.appendChild(test); + cntr.appendChild(document.createElement("br")); + var lbl = document.createElement("label"); + lbl.htmlFor = "ccf"; + lbl.innerHTML = "Copier la couleur depuis :"; + cntr.appendChild(lbl); + var inpt = document.createElement("select"); + inpt.name = "ccf"; + inpt.id = "ccf"; + cntr.appendChild(inpt); + cntr.appendChild(document.createElement("br")); + cntr.appendChild(document.createElement("br")); + var inpt = document.createElement("input"); + inpt.type = "submit"; + inpt.value = "Valider"; + cntr.appendChild(inpt); + formulaire.appendChild(cntr); + $('contenu').appendChild(formulaire); +} + +function GSM_addAlbum_chColor(type) +{ + var liste; + if (type == 1) + liste = GSM_liste_CDA; + else if (type == 2) + liste = GSM_liste_CDC; + else + liste = GSM_liste_CDD; + + $("ccf").innerHTML = ''; + + for (var i in liste) + { + if (Math.floor(i) == i) + { + var opt = document.createElement("option"); + opt.value = i; + opt.innerHTML = liste[i]; + $("ccf").appendChild(opt); + } + } + + if ($("ccf").innerHTML != "") + $("ccf").onchange = function(event) { if (this.value > 0) GSM_addAlbum_loadColor(this, type); }; +} + +function GSM_addAlbum_loadColor(elt, type) +{ + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "action", a: "GSM", p: "color", type: type, id: elt.value}, + onSuccess: function(transport, json) + { + $('color').value = transport.responseXML.documentElement.getElementsByTagName("color")[0].firstChild.textContent; + $("testColor").style.backgroundColor = $('color').value; + } + }); +} + +function newAlbum() +{ + var type; + if ($('cda').checked == 1) + type = 1; + else if ($('cdc').checked == 1) + type = 2; + else if ($('cdd').checked == 1) + type = 3; + else + { + alert("Vous n'avez pas sélectionné de type !"); + return; + } + + var nom = $('nom').value; + if (nom) + { + //On ajoute l'album + new Ajax.Request( + 'ajax.php?d=action&a=GSM&p=add', + { + method: 'post', + parameters: {type: type, title: nom, color: $('color').value}, + onSuccess: function(transport, json) + { + if (json.statut != 1) + { + firstLoad(); + alert("Vous avez été déconnecté. L'album' n'a pas été ajouté."); + } + else + { + if (transport.responseXML.documentElement.getElementsByTagName("id")[0]) + { + if (type == 1) + GSM_liste_CDA = false; + else if (type == 2) + GSM_liste_CDC = false; + else + GSM_liste_CDD = false; + + //On recharge la liste d'album + GSM_loadSelectedList(); + + $('contenu').innerHTML = ""; + titre = document.createElement("h2"); + titre.style.color = "#FF8800"; + titre.innerHTML = 'Chargement en cours ... Veuilez patienter'; + $('contenu').appendChild(titre); + + //On passe à l'écran de modification du nouvel album + GSM_viewalbum(type, transport.responseXML.documentElement.getElementsByTagName("id")[0].textContent, 0); + } + else + alert("L'ajout de l'album ne s'est pas passé correctement.") + } + }, + onFailure: function() { printEtat(3); } + } + ); + } + else + alert("Vous n'avez pas précisé de nom pour ce nouvel album."); +} + +function GSM_addForm(type, idAlbum, modif, page) +{ + //Si le formulaire existe déjà, on ne fait que remplacer son contenu + var formulaire; + if ($('ajout')) + { + formulaire = $('ajout'); + formulaire.innerHTML = ""; + } + else + { + formulaire = document.createElement("form"); + formulaire.id = "ajout"; + $('contenu').appendChild(formulaire); + } + + formulaire.onsubmit = function() { checkAndAdd(type, idAlbum, modif, page); return false; } + var th = document.createElement("h3"); + if (modif) + th.innerHTML = "Modification d'un titre"; + else + th.innerHTML = "Ajout d'un titre à l'album"; + + var lab_nom = document.createElement("label"); + lab_nom.innerHTML = "Titre :"; + lab_nom.forHTML = "titrechan"; + var inp_nom = document.createElement("input"); + if(modif) + inp_nom.value = GSM_liste[modif-1][1]; + inp_nom.type = "text"; + inp_nom.maxLength = "250"; + inp_nom.id = "titrechan"; + + var lab_carac = document.createElement("label"); + lab_carac.innerHTML = "Interpréte :"; + lab_carac.setAttribute("for", "auteur"); + var inp_carac = document.createElement("input"); + if(modif) + inp_carac.value = GSM_liste[modif-1][2]; + inp_carac.type = "text"; + inp_carac.maxLength = "250"; + inp_carac.id = "auteur"; + + var auteur_propos = document.createElement("div"); + auteur_propos.id = "auteur_propositions"; + auteur_propos.className = "autocomplete"; + + var inp_submit = document.createElement("input"); + inp_submit.type = "submit"; + if (modif) + inp_submit.value = "Modifier"; + else + inp_submit.value = "Ajouter"; + inp_submit.style.marginLeft = "165px"; + + formulaire.appendChild(th); + formulaire.appendChild(lab_nom); + formulaire.appendChild(inp_nom); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(lab_carac); + formulaire.appendChild(inp_carac); + formulaire.appendChild(auteur_propos); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(inp_submit); + if (modif) + { + var inp_del = document.createElement("input"); + inp_del.type = "button"; + inp_del.value = "Supprimer"; + inp_del.onclick = function() { GSM_del(type, idAlbum, modif, page); }; + inp_del.style.marginLeft = "15px"; + formulaire.appendChild(inp_del); + } + if (modif) + $('titrechan').focus(); + + new Ajax.Autocompleter( + "auteur", + "auteur_propositions", + "applications/GSM/auteurs.php", + { + paramName: 'auteur', + minChars: 1 + }); +} + +function GSM_checkChange(e) +{ + if (this.value == "add") + { + if (this.id == "discAuteur") + id_name = "new_auteur"; + else if (this.id == "discDece") + id_name = "new_decenie"; + else if (this.id == "discAnnee") + id_name = "new_annee"; + + document.getElementById(id_name).style.display = "inline"; + if (document.getElementById(id_name).value == "") + document.getElementById(id_name).value = "Nom du nouvel l'album"; + document.getElementById(id_name).focus(); + document.getElementById(id_name).select(); + } + else if (this.id == "discAuteur") + document.getElementById("new_auteur").style.display = "none"; + else if (this.id == "discDece") + document.getElementById("new_decenie").style.display = "none"; + else if (this.id == "discAnnee") + document.getElementById("new_annee").style.display = "none"; +} + +function GSM_del(type, idAlbum, modif, page) +{ + $('titrechan').disabled = true; + $('auteur').disabled = true; + + new Ajax.Request( + 'ajax.php?d=action&a=GSM&p=del', + { + method: 'post', + parameters: {id: GSM_rech.getElementsByTagName("chanson")[modif-1].getAttribute("id")}, + onSuccess: function(transport, json) + { + if (json.statut != 1) + { + firstLoad(); + alert("Vous avez été déconnecté. La chanson n'a pas été enregistrée"); + } + else + { + setTimeout('$("confirm").innerHTML = "Chanson supprimée avec succès !";', 234); + setTimeout("$('confirm').innerHTML = '';", 3500); + + $('nbpc').innerHTML = json.nombre; + + if (type) + GSM_viewalbum(type, idAlbum, page); + else + GSM_viewalbum(type, idAlbum, page); + + if (modif) + window.scrollTo(0,0); + } + }, + onFailure: function() { printEtat(3); } + } + ); + + //On réinitialise les variables de liste pour aller rechercher les listes + GSM_liste = false; + GSM_pagination = false; + $('contenu').innerHTML = "

Veuillez patienter suppression de la chanson en cours ...

"; +} + +function checkAndAdd(type, idAlbum, modif, page) +{ + var modifURI; + if(modif) + modifURI = "&id=" + GSM_liste[modif-1][0]; + else + modifURI = ""; + + if ($('titrechan').value == "") + { + $('titrechan').className = "erreur"; + alert('Vous n\'avez pas indiqué le titre de la chanson !'); + } + else if ($('auteur').value == "") + { + $('auteur').className = "erreur"; + alert('Vous n\'avez pas indiqué l\'auteur de la chanson !'); + } + else + { + $('titrechan').disabled = true; + $('auteur').disabled = true; + + new Ajax.Request( + 'ajax.php?d=action&a=GSM' + modifURI, + { + method: 'post', + parameters: {titre: $('titrechan').value, auteur: $('auteur').value, type: type, alb: idAlbum}, + onSuccess: function(transport, json) + { + if (json.statut != 1) + { + firstLoad(); + alert("Vous avez été déconnecté. La chanson n'a pas été enregistrée"); + } + else + { + if(modif) + { + setTimeout('$("confirm").innerHTML = "Chanson modifiée avec succès !";', 234); + setTimeout("$('confirm').innerHTML = '';", 3500); + + GSM_liste[modif-1][1] = $('titrechan').value; + GSM_liste[modif-1][2] = $('auteur').value; + } + else + { + GSM_origin_liste.push([transport.responseXML.documentElement.getElementsByTagName("id")[0].textContent, $('titrechan').value, $('auteur').value, (type==1?idAlbum:0), (type==2?idAlbum:0), (type==3?idAlbum:0)]); + $('titrechan').value = ""; + $('auteur').value = ""; + + $('titrechan').disabled = false; + $('auteur').disabled = false; + + $('nbpc').innerHTML = json.nombre; + + setTimeout('$("confirm").innerHTML = "Chanson ajoutée avec succès !";', 234); + setTimeout("$('confirm').innerHTML = '';", 3500); + } + + if (type) + GSM_viewalbum(type, idAlbum, page); + else + //TODO à tester ça marche pas + GSM_viewliste(null, null, page); + + if (modif) + window.scrollTo(0,0); + else + $('titrechan').focus(); + } + }, + onFailure: function() { printEtat(3); } + } + ); + } +} + +function GSM_viewalbums() +{ + if (GSM_origin_liste == false) + setTimeout(GSM_viewalbums, 200); + else + { + var tableau = document.createElement("div"); + tableau.className = "table cols2 stats"; + tableau.id = "statsA"; + var tableau_head = document.createElement("div"); + tableau_head.className = "head"; + var head_th = document.createElement("span"); + head_th.innerHTML = "CD années"; + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Nombre"; + tableau_head.appendChild(head_th); + tableau.appendChild(tableau_head); + var tableau_bodyA = document.createElement("div"); + tableau_bodyA.className = "body"; + tableau_bodyA.innerHTML = '
Chargement de la liste ... Veuillez patienter
'; + tableau.appendChild(tableau_bodyA); + $('contenu').appendChild(tableau); + + var tableau = document.createElement("div"); + tableau.className = "table cols2 stats"; + tableau.id = "statsC"; + var tableau_head = document.createElement("div"); + tableau_head.className = "head"; + var head_th = document.createElement("span"); + head_th.innerHTML = "CD chanteurs"; + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Nombre"; + tableau_head.appendChild(head_th); + tableau.appendChild(tableau_head); + var tableau_bodyC = document.createElement("div"); + tableau_bodyC.className = "body"; + tableau_bodyC.innerHTML = '
Chargement de la liste ... Veuillez patienter
'; + tableau.appendChild(tableau_bodyC); + $('contenu').appendChild(tableau); + + var tableau = document.createElement("div"); + tableau.className = "table cols2 stats"; + tableau.id = "statsD"; + var tableau_head = document.createElement("div"); + tableau_head.className = "head"; + var head_th = document.createElement("span"); + head_th.innerHTML = "CD décénies"; + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Nombre"; + tableau_head.appendChild(head_th); + tableau.appendChild(tableau_head); + var tableau_bodyD = document.createElement("div"); + tableau_bodyD.className = "body"; + tableau_bodyD.innerHTML = '
Chargement de la liste ... Veuillez patienter
'; + tableau.appendChild(tableau_bodyD); + $('contenu').appendChild(tableau); + + + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "action", a: "GSM", p: "stats"}, + onSuccess: function(transport, json) + { + var annees = transport.responseXML.documentElement.getElementsByTagName("annee"); + var chanteurs = transport.responseXML.documentElement.getElementsByTagName("interprete"); + var decenies = transport.responseXML.documentElement.getElementsByTagName("decenie"); + + tableau_bodyA.innerHTML = ""; + for (var i = 0; i < annees.length; i++) + { + if (annees[i].getAttribute("id") != "") + { + var lign = document.createElement("div"); + lign.className = "elt" + (i%2); + GSM_addStatLign(lign, 1, annees[i].getAttribute("id")); + var col = document.createElement("span"); + col.innerHTML = GSM_liste_CDA[annees[i].getAttribute("id")]; + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = annees[i].getAttribute("nbTitles"); + lign.appendChild(col); + tableau_bodyA.appendChild(lign); + } + } + if (annees.length == 0) + tableau_bodyA.innerHTML = '
Aucun CD
'; + else + lign.className += " foot"; + + tableau_bodyC.innerHTML = ""; + for (var i = 0; i < chanteurs.length; i++) + { + if (chanteurs[i].getAttribute("id") != "") + { + var lign = document.createElement("div"); + lign.className = "elt" + (i%2); + GSM_addStatLign(lign, 2, chanteurs[i].getAttribute("id")); + var col = document.createElement("span"); + col.innerHTML = GSM_liste_CDC[chanteurs[i].getAttribute("id")]; + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = chanteurs[i].getAttribute("nbTitles"); + lign.appendChild(col); + tableau_bodyC.appendChild(lign); + } + } + if (chanteurs.length == 0) + tableau_bodyC.innerHTML = '
Aucun CD
'; + else + lign.className += " foot"; + + tableau_bodyD.innerHTML = ""; + for (var i = 0; i < decenies.length; i++) + { + if (decenies[i].getAttribute("id") != "") + { + var lign = document.createElement("div"); + lign.className = "elt" + (i%2); + GSM_addStatLign(lign, 3, decenies[i].getAttribute("id")); + var col = document.createElement("span"); + col.innerHTML = GSM_liste_CDD[decenies[i].getAttribute("id")]; + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = decenies[i].getAttribute("nbTitles"); + lign.appendChild(col); + tableau_bodyD.appendChild(lign); + } + } + if (decenies.length == 0) + tableau_bodyD.innerHTML = '
Aucun CD
'; + else + lign.className += " foot"; + }, + onFailure: function() { printEtat(3); } + } + ); + } +} + +function GSM_addStatLign(lign, type, id) +{ + lign.onclick = function() { window.scrollTo(0,0); GSM_viewalbum(type, id, 0) }; +} + +function GSM_viewalbum(type, id, page) +{ + $('contenu').innerHTML = ""; + var confirmation = document.createElement("h2"); + confirmation.style.color = "teal"; + confirmation.id = "confirm"; + + var titre = document.createElement("h2"); + if (type == 2) + { + titre.innerHTML = "Liste des titres de " + GSM_liste_CDC[id]; + $('contenu').appendChild(titre); + $('contenu').appendChild(confirmation); + GSM_delay_viewalbum(2, id, page); + } + else if (type == 3) + { + titre.innerHTML = "Liste des titres de " + GSM_liste_CDD[id]; + $('contenu').appendChild(titre); + $('contenu').appendChild(confirmation); + GSM_delay_viewalbum(3, id, page); + } + else + { + titre.innerHTML = "Liste des titres de " + GSM_liste_CDA[id]; + $('contenu').appendChild(titre); + $('contenu').appendChild(confirmation); + GSM_delay_viewalbum(1, id, page); + } +} + +function GSM_delay_viewalbum(type, id, page) +{ + if (GSM_origin_liste == false) + GSM_delay = setTimeout(GSM_delay_viewalbum, 200, type, id, page); + else + { + GSM_liste = new Array(); + for (var i = 0; i < GSM_origin_liste.length; i++) + { + if (GSM_origin_liste[i][type+2] == id) + GSM_liste.push(GSM_origin_liste[i]); + } + if (GSM_liste == false) + GSM_liste[0] = 2; + + GSM_lastSort = -1; + + GSM_viewliste(type, id, page); + + GSM_addForm(type, id, false, 0); + } +} + +function GSM_viewliste(type, idAlbum, page) +{ + var pagination = document.createElement("div"); + pagination.className = "pagination top"; + pagination.id = "pagination1"; + $('contenu').appendChild(pagination); + + var tableau = document.createElement("div"); + tableau.className = "table cols3"; + tableau.id = "list"; + var tableau_head = document.createElement("div"); + tableau_head.className = "head"; + var head_th = document.createElement("span"); + head_th.innerHTML = "Titre"; + head_th.onclick = function() { GSM_showliste(1, 0, type, idAlbum); } + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Chanteur"; + head_th.onclick = function() { GSM_showliste(2, 0, type, idAlbum); } + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "CDs"; + head_th.style.cursor = "auto"; + tableau_head.appendChild(head_th); + tableau.appendChild(tableau_head); + var tableau_body = document.createElement("div"); + tableau_body.className = "body"; + tableau_body.id = "bodyList"; + tableau_body.innerHTML = '
Chargement de la liste en cours ... Veuillez patienter
'; + tableau.appendChild(tableau_body); + $('contenu').appendChild(tableau); + + + var pagination = document.createElement("div"); + pagination.className = "pagination bottom"; + pagination.id = "pagination2"; + $('contenu').appendChild(pagination); + + GSM_showliste(-1, page, type, idAlbum); +} + +function GSM_showliste(tri, page, type, idAlbum) +{ + if (GSM_origin_liste == false) + setTimeout(GSM_showliste, 200, tri, page, type, idAlbum); + else + { + if (GSM_liste == false) + GSM_liste = GSM_origin_liste; + + //On tente un tri + if (GSM_lastSort != tri) + { + $('bodyList').innerHTML = '
Tri de la liste en cours ...
'; + GSM_liste = GSM_liste.sort(function(a,b){return a[tri].localeCompare(b[tri]);}); + GSM_lastSort = tri; + } + + nbPages = Math.ceil(GSM_liste.length / nbParPage); + $('pagination1').innerHTML = ""; + $('pagination2').innerHTML = ""; + + if (nbPages < 3) + { + var lnkP = document.createElement("a"); + lnkP.href = "javascript:GSM_printliste(" + GSM_lastSort + ", " + type + ", " + idAlbum + ");"; + lnkP.innerHTML = "Imprimer la pochette"; + $('pagination1').appendChild(lnkP); + var lnkP = document.createElement("a"); + lnkP.href = "javascript:GSM_printliste(" + GSM_lastSort + ", " + type + ", " + idAlbum + ");"; + lnkP.innerHTML = "Imprimer la pochette"; + $('pagination2').appendChild(lnkP); + } + + for (var i = 0; i < 4 && i < nbPages; i++) + GSM_addLinkPagination(i, type, idAlbum); + if (page > 5 && i < nbPages) + { + $('pagination1').innerHTML += "..."; + $('pagination2').innerHTML += "..."; + } + for (var i = (page < 6?4:page - 2); (i < page + 3 && i < nbPages); i++) + GSM_addLinkPagination(i, type, idAlbum); + if (page <= 5 && i < nbPages) + { + $('pagination1').innerHTML += "..."; + $('pagination2').innerHTML += "..."; + for (var i = Math.ceil(nbPages/2) - 2; i < nbPages/2 + 2; i++) + GSM_addLinkPagination(i, type, idAlbum); + } + if (page + 3 < nbPages - 4) + { + $('pagination1').innerHTML += "..."; + $('pagination2').innerHTML += "..."; + } + for (var i = (page + 3 >= nbPages - 4?page + 3:nbPages - 4); (i < nbPages); i++) + GSM_addLinkPagination(i, type, idAlbum); + + start = page * nbParPage; + $('bodyList').innerHTML = ""; + + if (GSM_liste[0] != 2) + { + for (var i = 0; i < nbParPage && i + start < GSM_liste.length; i++) + { + var lign = document.createElement("div"); + lign.className = "elt" + (i%2); + + GSM_addLinkCD(lign, i + start, idAlbum, type, page); + var col = document.createElement("span"); + col.innerHTML = GSM_liste[i + start][1]; + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = GSM_liste[i + start][2]; + lign.appendChild(col); + var col = document.createElement("span"); + if (GSM_liste[i + start][3] != 0) + col.innerHTML += GSM_liste_CDA[GSM_liste[i + start][3]] + "
"; + if (GSM_liste[i + start][4] != 0) + col.innerHTML += GSM_liste_CDC[GSM_liste[i + start][4]] + "
"; + if (GSM_liste[i + start][5] != 0) + col.innerHTML += GSM_liste_CDD[GSM_liste[i + start][5]]; + lign.appendChild(col); + $('bodyList').appendChild(lign); + } + } + else + { + var lign = document.createElement("div"); + lign.className = "elt0"; + lign.innerHTML = "Il n'y a aucun titre enregistré dans cet album."; + $('bodyList').appendChild(lign); + } + lign.className += " foot"; + } +} +function GSM_addLinkPagination(page, type, idAlbum) +{ + var lnkP = document.createElement("a"); + lnkP.href = "javascript:GSM_showliste(" + GSM_lastSort + ", " + page + ", " + type + ", " + idAlbum + ");"; + lnkP.innerHTML = page+1; + $('pagination1').appendChild(lnkP); + var lnkP = document.createElement("a"); + lnkP.href = "javascript:GSM_showliste(" + GSM_lastSort + ", " + page + ", " + type + ", " + idAlbum + ");"; + lnkP.innerHTML = page+1; + $('pagination2').appendChild(lnkP); +} + +function GSM_printliste(tri, type, idAlbum) +{ + if (GSM_origin_liste == false) + setTimeout(GSM_printliste, 200, tri, type, idAlbum); + else + { + $('contenu').innerHTML = ""; + + var listeT; + if (type == 2) + listeT = GSM_liste_CDC; + else if (type == 3) + listeT = GSM_liste_CDD; + else + listeT = GSM_liste_CDA; + + var patt1 = listeT[idAlbum].match(/cd ?([0-9]+)/i).toString(); + var trueTitleL1 = listeT[idAlbum]; + trueTitleL1 = trueTitleL1.substr(0, trueTitleL1.length - patt1.indexOf(',')); + if (type == 1) + trueTitleL1 = "Année " + trueTitleL1; + + var trueTitleL2; + if (patt1) + trueTitleL2 = "CD " + patt1.substr(patt1.indexOf(',')+1); + else + trueTitleL2 = ""; + + var trueTitle = trueTitleL1 + " – " + trueTitleL2; + + var front = document.createElement("div"); + front.className = "front"; + var titleP = document.createElement("div"); + titleP.className = "title"; + titleP.innerHTML = trueTitleL1; + front.appendChild(titleP); + var cd = document.createElement("div"); + cd.className = "cd"; + cd.innerHTML = trueTitleL2; + if (trueTitleL2) + cd.style.marginTop = "70px"; + front.appendChild(cd); + $('contenu').appendChild(front); + + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "action", a: "GSM", p: "color", type: type, id: idAlbum}, + onSuccess: function(transport, json) + { + var colors = transport.responseXML.documentElement.getElementsByTagName("color"); + if (colors.length == 2) + { + titleP.style.color = colors[1].firstChild.textContent; + cd.style.color = colors[0].firstChild.textContent; + } + else if (colors.length == 1) + { + titleP.style.color = colors[0].firstChild.textContent; + cd.style.color = colors[0].firstChild.textContent; + } + } + }); + + var sp = document.createElement("div"); + sp.className = "sp"; + $('contenu').appendChild(sp); + + var back = document.createElement("div"); + back.className = "back"; + var backL = document.createElement("div"); + backL.className = "left"; + var title = document.createElement("div"); + title.className = "title"; + title.innerHTML = trueTitleL1 + " " + trueTitleL2; + backL.appendChild(title); + back.appendChild(backL); + var backR = document.createElement("div"); + backR.className = "right"; + var title = document.createElement("div"); + title.className = "title"; + title.innerHTML = trueTitleL1 + " " + trueTitleL2; + backR.appendChild(title); + back.appendChild(backR); + + var backC = document.createElement("div"); + backC.className = "center"; + var title = document.createElement("div"); + title.className = "title"; + title.innerHTML = trueTitleL1 + " – " + trueTitleL2; + backC.appendChild(title); + + var listeC = document.createElement("ol"); + backC.appendChild(listeC); + + back.appendChild(backC); + $('contenu').appendChild(back); + + if (GSM_liste == false) + GSM_liste = GSM_origin_liste; + + //On tente un tri + if (GSM_lastSort != tri) + { + GSM_liste = GSM_liste.sort(function(a,b){return a[tri].localeCompare(b[tri]);}); + GSM_lastSort = tri; + } + + if (GSM_liste[0] != 2) + { + for (var i = 0; i < GSM_liste.length; i++) + { + var lign = document.createElement("li"); + lign.className = "elt" + (i%2); + lign.innerHTML = GSM_liste[i + start][1] + var col = document.createElement("span"); + col.className = "author"; + col.innerHTML = GSM_liste[i + start][2]; + lign.appendChild(col); + GSM_addLinkOrder(lign, i + start, tri, type, idAlbum); + listeC.appendChild(lign); + } + + //On ajuste automatiquement la taille de la police + listeC.style.fontSize = Math.floor(4000/(GSM_liste.length*1.35))/10 + "px"; + listeC.style.marginTop = ((400 - listeC.clientHeight) / 2) + "px"; + } + else + { + var lign = document.createElement("div"); + lign.className = "elt0"; + lign.innerHTML = "Il n'y a aucun titre enregistré dans cet album."; + $('bodyList').appendChild(lign); + } + lign.className += " foot"; + } +} + +function GSM_addLinkCD(elt, idTitle, idAlbum, type, page) +{ + elt.onclick = function() { + GSM_addForm(type, idAlbum, idTitle+1, page); + } +} + +function GSM_addLinkOrder(elt, id, tri, type, idAlbum) +{ + elt.onclick = function() { + GSM_chOrder(id, tri, type, idAlbum); + } +} +function GSM_chOrder(id, tri, type, idAlbum) +{ + var num = prompt("Quel est le numéro de cette chanson : ", id+1); + if (num > 0 && num <= GSM_liste.length) + { + if (num != id) + { + var tmp = GSM_liste[num-1]; + GSM_liste[num-1] = GSM_liste[id]; + GSM_liste[id] = tmp; + + GSM_printliste(tri, type, idAlbum); + } + } + else + alert("Ce nombre n'est pas valide !\nLe numéro de la chanson doit être compris entre 1 et " + GSM_liste.length); +} + +function GSM_apropos() +{ + aproposApp("GSM", "contenu"); +} \ No newline at end of file diff --git a/applications/GSM/auteurs.php b/applications/GSM/auteurs.php new file mode 100644 index 0000000..7b6aae7 --- /dev/null +++ b/applications/GSM/auteurs.php @@ -0,0 +1,28 @@ +escape($nom); +$chanteurs = $bdd->query("SELECT chanteur FROM gsm WHERE chanteur LIKE '$nom%' GROUP BY chanteur;"); +$bdd->deconnexion(); + +if (!empty($chanteurs) && !empty($nom)) +{ + print ""; +} +?> \ No newline at end of file diff --git a/applications/GSM/loader.gif b/applications/GSM/loader.gif new file mode 100644 index 0000000..6e44c0e Binary files /dev/null and b/applications/GSM/loader.gif differ diff --git a/applications/GSM/main.css b/applications/GSM/main.css new file mode 100644 index 0000000..0ba0740 --- /dev/null +++ b/applications/GSM/main.css @@ -0,0 +1,99 @@ +.front +{ + border: solid 1px black; + display: table-cell; + height: 11.5cm; + text-align: center; + vertical-align: middle; + width: 11.5cm; +} + +.front .title, .front .cd +{ + font-size: 60px; + font-family: sans-serif; + font-weight: bolder; + text-transform: uppercase; +} + +.sp +{ + margin: 1cm 0; +} + +.back +{ + border: solid 1px black; + display: table; + height: 11.1cm; + width: 14.4cm; +} + +.back .title +{ + font-variant: small-caps +} + +.back .center .title +{ + font-size: 14px; + font-weight: bolder; +} + +.back .left, .back .right +{ + display: block; + height: 11.1cm; + text-align: left; + vertical-align: top; + width: 0.7cm; +} +.back .left +{ + border-right: dashed 1px gray; + float: left; +} +.back .right +{ + border-left: dashed 1px gray; + float: right; +} +.back .left .title, .back .right .title +{ + font-size: 13pt; + font-weight: bolder; + margin-top: 5.5cm; + margin-left: -5.15cm; + position: absolute; +} + +.back .left .title +{ + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + text-align: center; + width: 11.1cm; +} +.back .right .title +{ + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + text-align: center; + width: 11cm; +} + +.back .center +{ + text-align: center; +} + +.back ol +{ + text-align: left; +} + +.back .author +{ + float: right; + width: 50%; +} \ No newline at end of file diff --git a/applications/GSM/print.css b/applications/GSM/print.css new file mode 100644 index 0000000..ce1dcd3 --- /dev/null +++ b/applications/GSM/print.css @@ -0,0 +1,24 @@ +body +{ + font-family: serif; + font-size: 10px; + margin: auto; + width: 18cm; +} + +h1 { + display: none; +} +#GSM_menu { + display: none; +} + +.back .center +{ + overflow:hidden; + height: 11.1cm; +} +.back .center ol +{ + -webkit-margin-before: 0.5em; +} diff --git a/applications/GSM/style.css b/applications/GSM/style.css new file mode 100644 index 0000000..a2cbb4b --- /dev/null +++ b/applications/GSM/style.css @@ -0,0 +1,331 @@ +html { + height: 100%; +} + +body { + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0.31, #ffbe86), + color-stop(0.66, #ffebdb), + color-stop(1.00, #ffbe86) + ); + background: -moz-linear-gradient( + center bottom, + #ffbe86 31%, + #ffebdb 66%, + #ffbe86 100% + ); + + font-family: serif; + margin-bottom: 10px; + min-height: 80%; +} + +a:link, a:visited { + text-decoration: none; + color:#000000; +} + +h1 { + text-align: center; + margin-left: 250px; +} + +.pagination a:link, .pagination a:visited { + text-decoration: none; + color:#FFFFFF; +} + +.pagination a:hover, a:hover { + text-decoration: underline; +} + +.news { + background: -webkit-gradient( + linear, + left top, + right bottom, + color-stop(0.31, #ffa2a1), + color-stop(0.66, #ffdcdb) + ); + background: -moz-linear-gradient( + right bottom, + #ffa2a1 31%, + #ffdcdb 66% + ); + + border: 2px solid #ff6062; + border-radius: 17px; + box-shadow: 3px 4px 5px #444466; + + height: 127px; + margin: auto; + padding: 20px; + text-align: left; + width: 75%; +} + +.vp { + color: orange; +} + +#GSM_menu { + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0.31, #ffa2a1), + color-stop(0.90, #ffd3d3) + ); + background: -moz-linear-gradient( + center bottom, + #ffa2a1 31%, + #ffd3d3 90% + ); + + border-right: 2px dotted white; + color:#FFFFFF; + font-weight: bold; + height: 100%; + left: 0px; + list-style: none; + margin: 0; + -webkit-padding-start: 0; + position: fixed; + text-align: center; + top: 0px; + width: 250px; +} + +#GSM_menu h2 { + margin-left: 69px; +} + +#GSM_menu li { + margin-bottom: 40px; + text-align: center; + width: 250px; +} +#GSM_menu li[onclick] { + cursor: pointer; +} +#GSM_menu li[onclick]:hover { + text-decoration: underline; +} + +label { + font-weight: bold; +} +label:hover { + text-decoration: underline; +} + +form { + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0.31, #cc6d1d), + color-stop(0.95, #ff8f26) + ); + background: -moz-linear-gradient( + center bottom, + #cc6d1d 31%, + #ff8f26 95% + ); + border: 1px solid #ff9b42; + border-radius: 25px; + box-shadow: 2px 2px 5px #553333; +} + +form#addAlbms { + margin: auto; + padding: 13px; + text-align: left; + width: 345px; +} +form#addAlbms div { + text-align: center; +} +form#addAlbms div#testColor { + background-color: black; + border: solid 1px black; + display: inline-block; + height: 1em; + margin-left: 5px; + margin-bottom: -4px; + width: 2em; +} + +form#ajout { + height: 182px; + margin: 10px auto; + padding: 13px; + text-align: left; + width: 642px; +} +form#ajout input[type=text] { + width: 444px; +} +form#ajout select { + margin-right: 10px; +} + +form#ajout label { + float: left; + display: block; + font-weight: bold; + margin: 10px 7px 10px 0; + text-align: right; + width: 110px; +} +form#ajout label:hover { + text-decoration: underline; +} + +input[type=text], select { + margin: 10px 0; + transition: background 0.75s; + -moz-transition: background 0.75s; + -webkit-transition: background 0.75s; + -o-transition: background 0.75s; +} +input, select { + background: #FF6600; + border: #CA2A20 solid 1px; + border-radius: 3px; + margin-top: 5px; +} +input:hover, input:focus, select:hover, select:focus { + background: #CC6600; +} + +input.erreur, select.erreur { + background: #CC0000; +} + +div#GSM_menu { + background: url(backmenu.png); + color:#FFFFFF; + top: 0px; + font-weight: bold; + height: 1200px; + padding-top: 30px; + position: fixed; + text-align: center; + left: 0px; + width: 250px; +} + +div#GSM_menu h2 { + margin-bottom: 40px; +} + +div#contenu { + margin-left: 250px; + text-align: center; +} + +.table { + border: 1px solid black; + border-radius: 10px; + box-shadow: 3px 3px 5px #666666; + margin: auto; +} +.table .body div { + transition: background 500ms; + -moz-transition: background 500ms; + -webkit-transition: background 500ms; + -o-transition: background 500ms; +} +.table .body div.elt0 { + background: #ec7d60; +} +.table .body div.elt1 { + background: #f68063; +} +.table .body div:hover { + background: #fa8022; +} +.table.cols2 div span { + display: inline-block; + width: 40%; +} +.table.cols3 div span { + display: inline-block; + width: 40%; +} +.table.cols3 div span+span+span { + width: 20%; +} +.table div.lign { + display: inline-block; + width: 100%; +} + +.table .head { + background: #f26340; + border-bottom: 1px solid black; + border-radius: 10px 10px 0 0; + font-weight: bolder; + display: block; + text-align: center; + width: 100%; +} +.table .foot { border-radius: 0 0 10px 10px; } + +.table.stats { + float: left; + margin: 0 1%; + width: 31%; +} +.table#list { + width: 83%; +} +.table#list .head { + cursor: pointer; +} +.table .body div { + cursor: pointer; +} + +.pagination { + background: #f26340; + border: 1px solid black; + color: white; + margin: auto; + width: 442px; +} +.pagination.top { + border-radius: 10px 10px 0 0; + border-bottom: none; +} +.pagination.bottom { + border-top: none; + border-radius: 0 0 10px 10px; + box-shadow: 0px 2px 7px #666666; +} +.pagination a { + cursor: pointer; + padding: 0 5px; +} + +.front, .back +{ + background: white; +} +.back .center +{ + overflow:auto; +} +.back ol li:hover +{ + background-color: teal; +} + +div.autocomplete { + margin-top: 20px; + margin-left: 6px; +} \ No newline at end of file diff --git a/applications/GSPC/app.js b/applications/GSPC/app.js new file mode 100644 index 0000000..353228e --- /dev/null +++ b/applications/GSPC/app.js @@ -0,0 +1,537 @@ +var GSPC_origin_liste = false; +var GSPC_liste = false; +var GSPC_lastSort = -1; +var GSPC_delay = null; +var nbParPage = 50; + +//On charge la liste des porte-clés +function GSPC_loadList() +{ + GSPC_origin_liste = false; + GSPC_liste = false; + GSPC_lastSort = -1; + $('nbpc').innerHTML = 'Chargement en cours ...'; + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "action", a: "GSPC", p: "liste"}, + onSuccess: GSPC_parseList, + onFailure: function() { printEtat(3); } + } + ); +} +GSPC_loadList(); + +//Une fois la liste reçue, on la parse +function GSPC_parseList(transport, json) +{ + $('nbpc').innerHTML = json.nombre; + + var liste = transport.responseXML.documentElement.getElementsByTagName("liste")[0].getElementsByTagName("porteclef"); + GSPC_origin_liste = new Array(); + + for (var i = 0; i < liste.length; i++) + { + var elt = liste[i]; + GSPC_origin_liste.push([elt.getAttribute("id"), elt.getAttribute("nom"), elt.getAttribute("caracteristique"), elt.getAttribute("ligne"), elt.getAttribute("special")]) + } +} + +//Met en place le formulaire d'ajout de porte-clé +function GSPC_add() +{ + if (GSPC_delay) + clearTimeout(GSPC_delay); + + $('contenu').innerHTML = ""; + var titre = document.createElement("h2"); + titre.innerHTML = "Ajout d'un porte-clef à la base de données"; + $('contenu').appendChild(titre); + + GSPC_addScreen(false); +} + +//Affiche la liste des porte-clés +function GSPC_list() +{ + if (GSPC_delay) + clearTimeout(GSPC_delay); + + window.scrollTo(0,0); + + $('contenu').innerHTML = ""; + var titre = document.createElement("h2"); + titre.innerHTML = "Liste des porte-clefs"; + $('contenu').appendChild(titre); + + GSPC_liste = false; + GSPC_lastSort = -1; + + GSPC_viewliste(); +} + +//Affiche la page de statistiques +function GSPC_stats() +{ + if (GSPC_delay) + clearTimeout(GSPC_delay); + + window.scrollTo(0,0); + + $('contenu').innerHTML = ""; + var titre = document.createElement("h2"); + titre.innerHTML = "Statistiques"; + $('contenu').appendChild(titre); + + var tableau = document.createElement("div"); + tableau.className = "table cols2"; + tableau.id = "stats"; + var tableau_head = document.createElement("div"); + tableau_head.className = "head"; + var head_th = document.createElement("span"); + head_th.innerHTML = "Ligne"; + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Nombre"; + tableau_head.appendChild(head_th); + tableau.appendChild(tableau_head); + var tableau_body = document.createElement("div"); + tableau_body.className = "body"; + tableau_body.innerHTML = '
Téléchargement des statistiques en cours ... Veuillez patienter
'; + tableau.appendChild(tableau_body); + $('contenu').appendChild(tableau); + + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "action", a: "GSPC", p: "stats"}, + onSuccess: function(transport, json) + { + var stats = transport.responseXML.documentElement.getElementsByTagName("statistiques")[0]; + var nbPC = stats.getElementsByTagName("ligne").length; + + tableau_body.innerHTML = ""; + + for (var i = 0; i < nbPC; i++) + { + if (stats.getElementsByTagName("ligne")[i].getAttribute("nom") != "") + { + var lign = document.createElement("div"); + lign.className = "elt" + (i%2); + GSPC_addStatLign(lign, stats.getElementsByTagName("ligne")[i].getAttribute("nom")); + var col = document.createElement("span"); + col.innerHTML = stats.getElementsByTagName("ligne")[i].getAttribute("nom"); + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = stats.getElementsByTagName("ligne")[i].getAttribute("nombre"); + lign.appendChild(col); + tableau_body.appendChild(lign); + } + } + lign.className += " foot"; + }, + onFailure: function() { printEtat(3); } + } + ); +} + +function GSPC_addStatLign(lign, ligne) +{ + lign.onclick = function() { window.scrollTo(0,0); GSPC_viewligne(ligne) }; +} + +function GSPC_viewligne(ligne) +{ + $('contenu').innerHTML = ""; + var titre = document.createElement("h2"); + titre.innerHTML = "Liste des porte-clefs de la ligne " + ligne; + $('contenu').appendChild(titre); + + GSPC_delay_viewligne(ligne); +} + +function GSPC_delay_viewligne(ligne) +{ + if (GSPC_origin_liste == false) + GSPC_delay = setTimeout(GSPC_delay_viewligne, 200, ligne); + else + { + GSPC_liste = new Array(); + for (var i = 0; i < GSPC_origin_liste.length; i++) + { + if (GSPC_origin_liste[i][3] == ligne) + GSPC_liste.push(GSPC_origin_liste[i]); + } + GSPC_lastSort = -1; + + GSPC_viewliste(); + } +} + +function GSPC_addScreen(modif) +{ + formulaire = document.createElement("form"); + formulaire.id = "add" + formulaire.onsubmit = function(){ checkAndAdd(modif); return false; } + lab_nom = document.createElement("label"); + lab_nom.innerHTML = "Nom/marque :"; + lab_nom.setAttribute("for", "nompc"); + inp_nom = document.createElement("input"); + if(modif) + inp_nom.value = GSPC_liste[modif-1][1]; + inp_nom.type = "text"; + inp_nom.size = "34"; + inp_nom.maxLength = "250"; + inp_nom.id = "nompc"; + + lab_carac = document.createElement("label"); + lab_carac.innerHTML = "Caractéristiques :"; + lab_carac.setAttribute("for", "caracpc"); + inp_carac = document.createElement("input"); + if(modif) + inp_carac.value = GSPC_liste[modif-1][2]; + inp_carac.type = "text"; + inp_carac.size = "34"; + inp_carac.maxLength = "250"; + inp_carac.id = "caracpc"; + + lab_lign = document.createElement("label"); + lab_lign.innerHTML = "Ligne :"; + lab_lign.setAttribute("for", "lignepc"); + inp_lign = document.createElement("input"); + if(modif) + inp_lign.value = GSPC_liste[modif-1][3]; + inp_lign.type = "text"; + inp_lign.size = "10"; + inp_lign.maxLength = "3"; + inp_lign.id = "lignepc"; + + lab_quan = document.createElement("label"); + lab_quan.innerHTML = "Quantité :"; + lab_quan.setAttribute("for", "quantitepc"); + sel_quan = document.createElement("select"); + sel_quan.id = "quantitepc"; + sel_quan_1 = document.createElement("option"); + sel_quan_1.value = "1"; + sel_quan_1.innerHTML = "Simple"; + sel_quan_2 = document.createElement("option"); + sel_quan_2.value = "2"; + sel_quan_2.innerHTML = "Double"; + sel_quan_3 = document.createElement("option"); + sel_quan_3.value = "3"; + sel_quan_3.innerHTML = "Triple"; + sel_quan_4 = document.createElement("option"); + sel_quan_4.value = "4"; + sel_quan_4.innerHTML = "Quadruple"; + + inp_submit = document.createElement("input"); + inp_submit.type = "submit"; + if (modif) + inp_submit.value = "Modifier"; + else + inp_submit.value = "Ajouter"; + inp_submit.style.marginLeft = "165px"; + + formulaire.appendChild(lab_nom); + formulaire.appendChild(inp_nom); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(lab_carac); + formulaire.appendChild(inp_carac); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(lab_lign); + formulaire.appendChild(inp_lign); + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(lab_quan); + sel_quan.appendChild(sel_quan_1); + sel_quan.appendChild(sel_quan_2); + sel_quan.appendChild(sel_quan_3); + sel_quan.appendChild(sel_quan_4); + formulaire.appendChild(sel_quan); + formulaire.appendChild(document.createElement("br")); + if(modif) + sel_quan.value = GSPC_liste[modif-1][4]; + formulaire.appendChild(document.createElement("br")); + formulaire.appendChild(inp_submit); + if (modif) + { + inp_del = document.createElement("input"); + inp_del.type = "button"; + inp_del.value = "Supprimer"; + inp_del.onclick = function() { GSPC_del(modif); }; + inp_del.style.marginLeft = "15px"; + formulaire.appendChild(inp_del); + } + $('contenu').appendChild(formulaire); + $('nompc').focus(); + + confirmation = document.createElement("h3"); + confirmation.style.color = "teal"; + confirmation.id = "confirm"; + $('contenu').appendChild(confirmation); +} + +function GSPC_del(modif) +{ + $('nompc').disabled = true; + $('caracpc').disabled = true; + $('lignepc').disabled = true; + $('quantitepc').disabled = true; + + var ligne = GSPC_liste[modif-1][3]; + + new Ajax.Request( + 'ajax.php?d=action&a=GSPC&p=del', + { + method: 'post', + parameters: {id: GSPC_liste[modif-1][0]}, + onSuccess: function(transport, json) + { + if (json.statut != 1) + { + firstLoad(); + alert("Vous avez été déconnecté. Le porte-clef n'a pas été enregistré"); + } + else + { + $('contenu').innerHTML = ""; + confirmation = document.createElement("h2"); + confirmation.style.color = "teal"; + confirmation.innerHTML = "Porte-clef supprimé avec succès !"; + $('contenu').appendChild(confirmation); + $('nbpc').innerHTML = json.nombre; + + GSPC_loadList(); + GSPC_delay_viewligne(ligne); + } + }, + onFailure: function() { printEtat(3); } + } + ); + + $('contenu').innerHTML = "

Veuillez patienter suppression du porte-clef en cours ...

"; +} + +function checkAndAdd(modif) +{ + if(modif) + modif = "&id=" + GSPC_liste[modif-1][0]; + else + modif = ""; + + if ($('nompc').value == "") + { + $('nompc').className = "erreur"; + alert('Veuillez indiquer une marque ou un nom !'); + $('nompc').focus(); + } + else if ($('lignepc').value == "") + { + $('lignepc').className = "erreur"; + alert('Veuillez indiquer une ligne !'); + $('lignepc').focus(); + } + else + { + $('nompc').disabled = true; + $('caracpc').disabled = true; + $('lignepc').disabled = true; + $('quantitepc').disabled = true; + + new Ajax.Request( + 'ajax.php?d=action&a=GSPC' + modif, + { + method: 'post', + parameters: {nom: $('nompc').value, caracteristique: $('caracpc').value, ligne: $('lignepc').value, quantite: $('quantitepc').value}, + onSuccess: function(transport, json) + { + if (json.statut != 1) + { + firstLoad(); + alert("Vous avez été déconnecté. Le porte-clef n'a pas été enregistré"); + } + else + { + GSPC_loadList(); + + if(modif) + { + $('contenu').innerHTML = ""; + confirmation = document.createElement("h2"); + confirmation.style.color = "teal"; + confirmation.innerHTML = "Porte-clef modifié avec succès !"; + $('contenu').appendChild(confirmation); + $('nbpc').innerHTML = json.nombre; + + GSPC_delay_viewligne(lign); + } + else + { + $('nompc').value = ""; + $('nompc').className = ""; + $('caracpc').value = ""; + $('lignepc').className = ""; + $('quantitepc').value = 1; + + $('nompc').disabled = false; + $('caracpc').disabled = false; + $('lignepc').disabled = false; + $('quantitepc').disabled = false; + + $('nbpc').innerHTML = json.nombre; + + $('confirm').innerHTML = "Porte-clef ajouté avec succès !"; + setTimeout("$('confirm').innerHTML = '';", 3500); + + $('nompc').focus(); + } + } + }, + onFailure: function() { printEtat(3); } + } + ); + + if(modif) + { + lign = $('lignepc').value; + $('contenu').innerHTML = "

Veuillez patienter, modification du porte-clef en cours ...

"; + } + } +} + +function GSPC_viewliste() +{ + var pagination = document.createElement("div"); + pagination.className = "pagination top"; + pagination.id = "pagination1"; + $('contenu').appendChild(pagination); + + var tableau = document.createElement("div"); + tableau.className = "table cols3"; + tableau.id = "list"; + var tableau_head = document.createElement("div"); + tableau_head.className = "head"; + var head_th = document.createElement("span"); + head_th.innerHTML = "Nom/Marque"; + head_th.onclick = function(){ GSPC_showliste(1, 0); } + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Caractéristique"; + head_th.onclick = function(){ GSPC_showliste(2, 0); } + tableau_head.appendChild(head_th); + var head_th = document.createElement("span"); + head_th.innerHTML = "Ligne"; + head_th.onclick = function(){ GSPC_showliste(3, 0); } + tableau_head.appendChild(head_th); + tableau.appendChild(tableau_head); + var tableau_body = document.createElement("div"); + tableau_body.className = "body"; + tableau_body.id = "bodyList"; + tableau_body.innerHTML = '
Chargement de la liste en cours ... Veuillez patienter
'; + tableau.appendChild(tableau_body); + $('contenu').appendChild(tableau); + + var pagination = document.createElement("div"); + pagination.className = "pagination bottom"; + pagination.id = "pagination2"; + $('contenu').appendChild(pagination); + + GSPC_showliste(-1, 0); +} + +function GSPC_showliste(tri, page) +{ + if (GSPC_origin_liste == false) + setTimeout(GSPC_showliste, 200, tri); + else + { + if (GSPC_liste == false) + GSPC_liste = GSPC_origin_liste; + + //On tente un tri + if (GSPC_lastSort != tri) + { + $('bodyList').innerHTML = '
Tri de la liste en cours ...
'; + GSPC_liste = GSPC_liste.sort(function(a,b){return a[tri].localeCompare(b[tri]);}); + GSPC_lastSort = tri; + } + + nbPages = Math.ceil(GSPC_liste.length / nbParPage); + $('pagination1').innerHTML = ""; + $('pagination2').innerHTML = ""; + for (var i = 0; i < 4 && i < nbPages; i++) + GSPC_addLinkPagination(i); + if (page > 5 && i < nbPages) + { + $('pagination1').innerHTML += "..."; + $('pagination2').innerHTML += "..."; + } + for (var i = (page < 6?4:page - 2); (i < page + 3 && i < nbPages); i++) + GSPC_addLinkPagination(i); + if (page <= 5 && i < nbPages) + { + $('pagination1').innerHTML += "..."; + $('pagination2').innerHTML += "..."; + for (var i = Math.ceil(nbPages/2) - 2; i < nbPages/2 + 2; i++) + GSPC_addLinkPagination(i); + } + if (page + 3 < nbPages - 4) + { + $('pagination1').innerHTML += "..."; + $('pagination2').innerHTML += "..."; + } + for (var i = (page + 3 >= nbPages - 4?page + 3:nbPages - 4); (i < nbPages); i++) + GSPC_addLinkPagination(i); + + start = page * nbParPage; + $('bodyList').innerHTML = ""; + + for (var i = 0; i < nbParPage && i + start < GSPC_liste.length; i++) + { + var lign = document.createElement("div"); + lign.className = "elt" + (i%2); + GSPC_addLinkPC(lign, i + start); + var col = document.createElement("span"); + col.innerHTML = GSPC_liste[i + start][1]; + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = GSPC_liste[i + start][2]; + lign.appendChild(col); + var col = document.createElement("span"); + col.innerHTML = GSPC_liste[i + start][3]; + lign.appendChild(col); + $('bodyList').appendChild(lign); + } + lign.className += " foot" + } +} + +function GSPC_addLinkPagination(page) +{ + var lnkP = document.createElement("a"); + lnkP.href = "javascript:GSPC_showliste(" + GSPC_lastSort + ", " + page + ");"; + lnkP.innerHTML = page+1; + $('pagination1').appendChild(lnkP); + var lnkP = document.createElement("a"); + lnkP.href = "javascript:GSPC_showliste(" + GSPC_lastSort + ", " + page + ");"; + lnkP.innerHTML = page+1; + $('pagination2').appendChild(lnkP); +} + +function GSPC_addLinkPC(elt, idPC) +{ + elt.onclick = function() { + $('contenu').innerHTML = ""; + var titre = document.createElement("h2"); + titre.innerHTML = "Modification d'un porte-clef"; + $('contenu').appendChild(titre); + + GSPC_addScreen(idPC+1); + } +} + +function GSPC_apropos() +{ + aproposApp("GSPC", "contenu"); +} \ No newline at end of file diff --git a/applications/GSPC/loader.gif b/applications/GSPC/loader.gif new file mode 100644 index 0000000..e0b75a6 Binary files /dev/null and b/applications/GSPC/loader.gif differ diff --git a/applications/GSPC/loader1.gif b/applications/GSPC/loader1.gif new file mode 100644 index 0000000..74d53e0 Binary files /dev/null and b/applications/GSPC/loader1.gif differ diff --git a/applications/GSPC/style.css b/applications/GSPC/style.css new file mode 100644 index 0000000..9d2fa6a --- /dev/null +++ b/applications/GSPC/style.css @@ -0,0 +1,280 @@ +html { + height: 100%; +} + +body { + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0.31, #9eeaff), + color-stop(0.66, #e4f9ff), + color-stop(1.00, #9eeaff) + ); + background: -moz-linear-gradient( + center bottom, + #9eeaff 31%, + #e4f9ff 66%, + #9eeaff 100% + ); + + font-family: serif; + min-height: 80%; +} + +a:link, a:visited { + text-decoration: none; + color:#000000; +} + +h1 { + text-align: center; + margin-left: 250px; +} + +#GSPC_menu a:link, #GSPC_menu a:visited, .pagination a:link, .pagination a:visited { + text-decoration: none; + color:#FFFFFF; +} + +#GSPC_menu a:hover, .pagination a:hover, a:hover { + text-decoration: underline; +} + +.news { + background: -webkit-gradient( + linear, + left top, + right bottom, + color-stop(0.31, #93b4ff), + color-stop(0.66, #c5ceff) + ); + background: -moz-linear-gradient( + right bottom, + #93b4ff 31%, + #c5ceff 66% + ); + + border: 2px solid #5290ff; + border-radius: 17px; + box-shadow: 3px 4px 5px #444466; + + height: 127px; + margin: auto; + padding: 20px; + text-align: left; + width: 75%; +} + +.vp { + color: orange; +} + +#GSPC_menu { + background: -webkit-gradient( + linear, + left top, + left bottom, + color-stop(0.31, #5290ff), + color-stop(0.90, #a3c4ff) + ); + background: -moz-linear-gradient( + center bottom, + #5290ff 31%, + #a3c4ff 90% + ); + + border-right: 2px dotted white; + color:#FFFFFF; + font-weight: bold; + height: 100%; + left: 0px; + list-style: none; + margin: 0; + -webkit-padding-start: 0; + position: fixed; + text-align: center; + top: 0px; + width: 250px; +} + +#GSPC_menu h2 { + margin-left: 69px; +} + +#GSPC_menu li { + margin-bottom: 40px; + text-align: center; + width: 250px; +} +#GSPC_menu li[onclick] { + cursor: pointer; +} +#GSPC_menu li[onclick]:hover { + text-decoration: underline; +} + +span#nompc img { + margin-top: 3px; +} + +div#contenu { + margin-left: 250px; + text-align: center; +} + +form#add { + background: -webkit-gradient( + linear, + left top, + right bottom, + color-stop(0.31, #c9b5e8), + color-stop(0.95, #e4daf4) + ); + background: -moz-linear-gradient( + center bottom, + #c9b5e8 31%, + #e4daf4 95% + ); + + border: 1px solid #8A77A1; + border-radius: 25px; + box-shadow: 2px 2px 5px #333355; + height: 205px; + margin: auto; + padding: 13px; + text-align: left; + width: 456px; +} + +label { + float: left; + display: block; + font-weight: bold; + margin: 10px 7px 10px 0; + text-align: right; + width: 170px; +} +label:hover { + text-decoration: underline; +} + +input[type=text], select { + margin: 10px 0; + transition: background 0.75s; + -moz-transition: background 0.75s; + -webkit-transition: background 0.75s; + -o-transition: background 0.75s; +} +input, select { + background: #00EAF5; + border: #009AA5 solid 1px; + border-radius: 3px; + margin-top: 5px; +} +input:hover, input:focus, select:hover, select:focus { + background: #95cdff; +} + +input#nompc { + font-variant: small-caps; +} +input#lignepc { + text-transform:uppercase; +} + +input.erreur, select.erreur { + background: #CC0000; + border: #A59A00 solid 1px; +} + +.table { + border: 1px solid black; + border-radius: 10px; + box-shadow: 3px 3px 5px #666666; + margin: auto; +} +.table .body div { + transition: background 500ms; + -moz-transition: background 500ms; + -webkit-transition: background 500ms; + -o-transition: background 500ms; +} +.table .body div.elt0 { + background: #5c93a0; +} +.table .body div.elt1 { + background: #5c96a5; +} +.table .body div:hover { + background: #73B14b; +} +.table.cols2 div span { + display: inline-block; + width: 50%; +} +.table.cols3 div span { + display: inline-block; + width: 45%; +} +.table.cols3 div span+span+span { + width: 10%; +} +.table.cols3 div.body span { + text-transform: uppercase; +} +.table.cols3 div.body span+span { + text-transform: none; +} +.table.cols3 div.body span+span+span { + text-transform: uppercase; +} +.table div.lign { + display: inline-block; + width: 100%; +} + +.table .head { + background: #1070c9; + border-bottom: 1px solid black; + border-radius: 10px 10px 0 0; + font-weight: bolder; + display: block; + text-align: center; + width: 100%; +} +.table .foot { border-radius: 0 0 10px 10px; } + +.table#stats { + width: 42%; +} +.table#list { + width: 83%; +} +.table#list .head { + cursor: pointer; +} +.table .body div { + cursor: pointer; +} + +.pagination { + background: #1070c9; + border: 1px solid black; + color: white; + margin: auto; + width: 442px; +} +.pagination.top { + border-radius: 10px 10px 0 0; + border-bottom: none; +} +.pagination.bottom { + border-top: none; + border-radius: 0 0 10px 10px; + box-shadow: 0px 2px 7px #666666; +} +.pagination a { + cursor: pointer; + padding: 0 5px; +} \ No newline at end of file diff --git a/applications/chat/app.js b/applications/chat/app.js new file mode 100644 index 0000000..79f6cfd --- /dev/null +++ b/applications/chat/app.js @@ -0,0 +1,95 @@ +var chat_lastTime = 0; +var chat_refresh_time = 1500; + +function chat_MAJ() +{ + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {time: chat_lastTime, d: "action", a: "chat"}, + onSuccess: function(transport, json) { + if (json.messages.length > 0) + { + for(i=json.messages.length-1; i>=0; i--) + { + //On tranforme le timestamp en date correcte + var date = new Date(); + var now = new Date(); + date.setTime(json.messages[i]["timestamp"]*1000); + + //On affiche tout + var newRow = $('chat').insertRow(0); + var newCell = newRow.insertCell(0); + if (date.getDay() != now.getDay()) + newCell.innerHTML = '[' + json.messages[i]["pseudo"] + '] ' + (date.getDay()<10?"0"+date.getDay():date.getDay()) + "/" + (date.getMonth()<10?"0"+date.getMonth():date.getMonth()) + " " + (date.getHours()<10?"0"+date.getHours():date.getHours()) + ":" + (date.getMinutes()<10?"0"+date.getMinutes():date.getMinutes()) + ":" + (date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds()); + else + newCell.innerHTML = '[' + json.messages[i]["pseudo"] + '] ' + (date.getHours()<10?"0"+date.getHours():date.getHours()) + ":" + (date.getMinutes()<10?"0"+date.getMinutes():date.getMinutes()) + ":" + (date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds()); + newCell = newRow.insertCell(1); + newCell.innerHTML = json.messages[i]["message"]; + if (chat_lastTime < json.messages[i]["timestamp"]) + chat_lastTime = json.messages[i]["timestamp"]; + } + } + }, + onFailure: function() { chat_MAJ(); } + } + ); + chat_refresh = setTimeout("chat_MAJ()", chat_refresh_time); +} + +function chat_clearScreen() +{ + $('chat').innerHTML = ""; + chat_write("JS", "Nettoyage de l'écran"); +} + +function chat_refreshScreen() +{ + chat_refresh = setTimeout("chat_MAJ()", 1); +} + +function chat_reset() +{ + chat_lastTime = 0; +} + +function chat_changeRefreshTime(newTime) +{ + if (newTime > 0) + { + if (newTime < 999) + newTime *= 1000; + chat_refresh_time = newTime; + + chat_write("JS", "Temps de rafraîchissement passé à " + newTime/1000 + " seconde(s)"); + } +} + +function chat_sendCommande(commande) +{ + new Ajax.Request( + 'ajax.php?d=action&a=chat', + { + method: 'post', + parameters: {comm: commande}, + onSuccess: function(transport, json) { + if (json.confirm) + chat_write("Server", json.confirm); + else + chat_write("Server", "Rien"); + }, + onFailure: function() { alert("La requête a échouée!"); } + } + ); +} + +function chat_write(posteur, message) +{ + var date = new Date(); + var newRow = $('chat').insertRow(0); + var newCell = newRow.insertCell(0); + newCell.innerHTML = '' + posteur + ' ' + (date.getHours()<10?"0"+date.getHours():date.getHours()) + ":" + (date.getMinutes()<10?"0"+date.getMinutes():date.getMinutes()) + ":" + (date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds()); + newCell = newRow.insertCell(1); + newCell.innerHTML = "" + message + ""; +} \ No newline at end of file diff --git a/applications/users/app.js b/applications/users/app.js new file mode 100644 index 0000000..fb88de5 --- /dev/null +++ b/applications/users/app.js @@ -0,0 +1,217 @@ +var USERS_liste = false; + +function USERS_add() +{ + $('corps').innerHTML = ""; + USERS_display("add", false); +} + +function USERS_modif(id) +{ + $('corps').innerHTML = ""; + if (!USERS_liste) + USERS_loadListe(false); + + USERS_display("modif", USERS_liste[id]); +} + +function USERS_delete(id) +{ + alert("Demande de suppression de l'utilisateur : " + id); +} + +function USERS_loadListe(async) +{ + new Ajax.Request( + 'ajax.php', + { + method: 'get', + asynchronous: async, + parameters: {d: "action", a: "users"}, + onSuccess: function(transport, json) + { + USERS_liste = USERS_liste; + }, + onFailure: function() { printEtat(3); } + } + ); +} + +function USERS_display(page, plus) +{ + alert('pom'); + if (page == "add" || page == "modif") + { + formMod = document.createElement("form"); + if (plus) + formMod.onsubmit = function() { USERS_sendModif(plus.id); return false; } + else + formMod.onsubmit = USERS_sendAdd; + + fieldMod = document.createElement("fieldset"); + fieldMod.style.width = "500px"; + fieldMod.style.margin = "auto"; + fieldleg = document.createElement("legend"); + fieldleg.innerHTML = "Utilisateur"; + fieldMod.appendChild(fieldleg); + + labelchamp = document.createElement("label"); + labelchamp.innerHTML = "Nom :"; + labelchamp.setAttribute("for", "nom"); + fieldMod.appendChild(labelchamp); + fieldMod.innerHTML += " "; + inputchamp = document.createElement("input"); + inputchamp.type = "text"; + inputchamp.id = "nom"; + if (plus) + inputchamp.value = plus.pseudo; + fieldMod.appendChild(inputchamp); + + fieldMod.appendChild(document.createElement("br")); + + labelchamp = document.createElement("label"); + labelchamp.innerHTML = "Mot de passe :"; + labelchamp.setAttribute("for", "mdp"); + fieldMod.appendChild(labelchamp); + fieldMod.innerHTML += " "; + inputchamp = document.createElement("input"); + inputchamp.type = "password"; + inputchamp.id = "mdp"; + fieldMod.appendChild(inputchamp); + + fieldMod.appendChild(document.createElement("br")); + + labelchamp = document.createElement("label"); + labelchamp.innerHTML = "Confirmer mot de passe :"; + labelchamp.setAttribute("for", "conf"); + fieldMod.appendChild(labelchamp); + fieldMod.innerHTML += " "; + inputchamp = document.createElement("input"); + inputchamp.type = "password"; + inputchamp.id = "conf"; + fieldMod.appendChild(inputchamp); + + fieldMod.appendChild(document.createElement("br")); + fieldMod.appendChild(document.createElement("br")); + + labelchamp = document.createElement("label"); + labelchamp.innerHTML = "Adresse électronique :"; + labelchamp.setAttribute("for", "mail"); + fieldMod.appendChild(labelchamp); + fieldMod.innerHTML += " "; + inputchamp = document.createElement("input"); + inputchamp.type = "text"; + if (plus) + inputchamp.value = plus.mail; + inputchamp.id = "mail"; + fieldMod.appendChild(inputchamp); + + fieldMod.appendChild(document.createElement("br")); + fieldMod.appendChild(document.createElement("br")); + + inputchamp = document.createElement("input"); + inputchamp.type = "submit"; + inputchamp.value = "Continuer"; + fieldMod.appendChild(inputchamp); + formMod.appendChild(fieldMod); + $('corps').appendChild(formMod); + } + else + { + if (plus) + USERS_liste = plus.users; + + tableMessages = document.createElement("table"); + tableMessages.style.margin = "auto"; + tableMessages.style.width = "90%"; + theMess = document.createElement("thead"); + trMess = document.createElement("tr"); + thMess = document.createElement("th"); + thMess.innerHTML = "Action"; + trMess.appendChild(thMess); + thMess = document.createElement("th"); + thMess.innerHTML = "Utilisateur"; + trMess.appendChild(thMess); + thMess = document.createElement("th"); + thMess.innerHTML = "Adresse électronique"; + trMess.appendChild(thMess); + thMess = document.createElement("th"); + thMess.innerHTML = "Dernière connexion"; + trMess.appendChild(thMess); + thMess = document.createElement("th"); + thMess.innerHTML = "Dernière IP"; + trMess.appendChild(thMess); + theMess.appendChild(trMess); + tableMessages.appendChild(theMess); + tboMess = document.createElement("tbody"); + tboMess.id = "users"; + tableMessages.appendChild(tboMess); + $('corps').appendChild(tableMessages); + + nbUsers = USERS_liste.length; + for(i=0; iModifier'; + var newCell = newRow.insertCell(1); + newCell.innerHTML = USERS_liste[i].pseudo; + var newCell = newRow.insertCell(2); + newCell.innerHTML = USERS_liste[i].mail; + var newCell = newRow.insertCell(3); + newCell.innerHTML = (date.getDay()<10?"0"+date.getDay():date.getDay()) + "/" + (date.getMonth()<10?"0"+date.getMonth():date.getMonth()) + "/" + date.getFullYear() + " " + (date.getHours()<10?"0"+date.getHours():date.getHours()) + ":" + (date.getMinutes()<10?"0"+date.getMinutes():date.getMinutes()) + ":" + (date.getSeconds()<10?"0"+date.getSeconds():date.getSeconds()); + var newCell = newRow.insertCell(4); + newCell.innerHTML = USERS_liste[i].last_ip; + } + + var newRow = $('users').insertRow(-1); + var newCell = newRow.insertCell(0); + newCell.innerHTML = 'Ajouter'; + } +} + +function USERS_sendAdd() +{ + if ($('mdp').value.length < 5) + alert("Le mot de passe est trop court !\nIl doit faire au moins 5 caractères."); + else if ($('mdp').value != $('conf').value) + alert("Le mot de passe est sa confirmation est différent !"); + else + { + new Ajax.Request( + 'ajax.php?d=action&a=users', + { + method: 'post', + asynchronous: async, + parameters: {nom: $('nom').value, mdp: $('mdp').value, mail: $('mail').value}, + onSuccess: function(transport, json) + { + USERS_liste = json.users; + }, + onFailure: function() { printEtat(3); } + } + ); + } + + return false; +} + +function USERS_sendModif(id) +{ + if ($('mdp').value.length < 5) + alert("Le mot de passe est trop court !\nIl doit faire au moins 5 caractères."); + else if ($('mdp').value != $('conf').value) + alert("Le mot de passe est sa confirmation est différent !"); + else + { + alert("Demande de modification pour l'utilisateur ayant l'ID : " + id); + + + } + + $('mdp').value = ""; + $('conf').value = ""; +} \ No newline at end of file diff --git a/common.css b/common.css new file mode 100644 index 0000000..85d892f --- /dev/null +++ b/common.css @@ -0,0 +1,116 @@ +body { + background: url('images/background.jpg') fixed #E1E2E4; + font-family: sans-serif; +} + +#btMenu { + background-image: url('images/menu.png'); + height: 60px; + left: 10px; + position: fixed; + top: 1px; + width: 60px; + z-index: 10; +} +#btMenu:hover { + background-position: 0 -60px; +} +#btMenu:active { + background-position: 0 -120px; +} +#btMenu span { + display: none; +} + +.submenu +{ + background: #D6EDF8; + border: solid 1px #B6CDD8; + display: none; + padding: 0px; + text-align: left; + overflow: hidden; + z-index: 10; +} + +#menu { + margin: 10px; + position: fixed; + top: 5px; + left: 20px; + width: 155px; +} +#menu #nameApp { + font-family: serif; + text-align: center; + font-weight: bold; +} +#menu #nameApp, .submenu li.hr { + border-bottom: groove 3px gray; + margin-bottom: 2px; + padding-bottom: 3px; +} + +.submenu ul { + list-style: none; +} + +.submenu li.item { + color: #6BCCD6; + display: block; + line-height: 20px; + padding: 0 5px 0 5px; + text-decoration: none; +} +.submenu li.item:hover { + background-color: #797979; + text-decoration: none; +} + +div#etat { + background-color: #CDF; + border-right: solid 1px #89B; + border-top: solid 1px #89B; + border-radius: 5px; + bottom: 0px; + font-size: small; + font-style: italic; + left: 0px; + padding: 1px 4px; + position: fixed; +} + + +div.autocomplete { + position: absolute; + width: 500px; + background-color: white; + border: 1px solid #888; + margin: 0px; + padding: 0px; +} + +div.autocomplete ul { + list-style-type: none; + margin: 0px; + padding: 0px; + max-height: 20em; + overflow: auto; +} + +div.autocomplete ul li.selected { + background-color: #ffb; +} + +div.autocomplete ul li { + list-style-type:none; + display: block; + margin: 0; + padding: 2px; + cursor: pointer; +} + + +div.autocomplete ul li span.informal { + color: gray; +} \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..69df2c6 Binary files /dev/null and b/favicon.ico differ diff --git a/fonts/kidprint.ttf b/fonts/kidprint.ttf new file mode 100644 index 0000000..9426c8c Binary files /dev/null and b/fonts/kidprint.ttf differ diff --git a/images/background.jpg b/images/background.jpg new file mode 100644 index 0000000..983ddd6 Binary files /dev/null and b/images/background.jpg differ diff --git a/images/etats/alpha.png b/images/etats/alpha.png new file mode 100644 index 0000000..e9c228c Binary files /dev/null and b/images/etats/alpha.png differ diff --git a/images/etats/beta.png b/images/etats/beta.png new file mode 100644 index 0000000..28c087e Binary files /dev/null and b/images/etats/beta.png differ diff --git a/images/etats/construction.png b/images/etats/construction.png new file mode 100644 index 0000000..f7f0f9b Binary files /dev/null and b/images/etats/construction.png differ diff --git a/images/etats/final.png b/images/etats/final.png new file mode 100644 index 0000000..c8eaaea Binary files /dev/null and b/images/etats/final.png differ diff --git a/images/logog.png b/images/logog.png new file mode 100644 index 0000000..3db64cf Binary files /dev/null and b/images/logog.png differ diff --git a/images/menu.png b/images/menu.png new file mode 100644 index 0000000..64aa197 Binary files /dev/null and b/images/menu.png differ diff --git a/images/menu.xcf b/images/menu.xcf new file mode 100644 index 0000000..2848dfd Binary files /dev/null and b/images/menu.xcf differ diff --git a/images/pomme.png b/images/pomme.png new file mode 100644 index 0000000..6473cea Binary files /dev/null and b/images/pomme.png differ diff --git a/images/titres/403.png b/images/titres/403.png new file mode 100644 index 0000000..da39ef6 Binary files /dev/null and b/images/titres/403.png differ diff --git a/images/titres/403en.png b/images/titres/403en.png new file mode 100644 index 0000000..b4beaee Binary files /dev/null and b/images/titres/403en.png differ diff --git a/images/titres/404.png b/images/titres/404.png new file mode 100644 index 0000000..4459377 Binary files /dev/null and b/images/titres/404.png differ diff --git a/images/titres/404en.png b/images/titres/404en.png new file mode 100644 index 0000000..748f6ba Binary files /dev/null and b/images/titres/404en.png differ diff --git a/images/titres/UK.png b/images/titres/UK.png new file mode 100644 index 0000000..1d5aa47 Binary files /dev/null and b/images/titres/UK.png differ diff --git a/images/titres/US.png b/images/titres/US.png new file mode 100644 index 0000000..33b40d3 Binary files /dev/null and b/images/titres/US.png differ diff --git a/images/titres/abonnement.png b/images/titres/abonnement.png new file mode 100644 index 0000000..0a3cae5 Binary files /dev/null and b/images/titres/abonnement.png differ diff --git a/images/titres/abonnements.png b/images/titres/abonnements.png new file mode 100644 index 0000000..f551fc3 Binary files /dev/null and b/images/titres/abonnements.png differ diff --git a/images/titres/aboutthissite.png b/images/titres/aboutthissite.png new file mode 100644 index 0000000..4481cb0 Binary files /dev/null and b/images/titres/aboutthissite.png differ diff --git a/images/titres/accueil.png b/images/titres/accueil.png new file mode 100644 index 0000000..04bc1bc Binary files /dev/null and b/images/titres/accueil.png differ diff --git a/images/titres/achatenligne.png b/images/titres/achatenligne.png new file mode 100644 index 0000000..0e97cc8 Binary files /dev/null and b/images/titres/achatenligne.png differ diff --git a/images/titres/actualites.png b/images/titres/actualites.png new file mode 100644 index 0000000..7c169fd Binary files /dev/null and b/images/titres/actualites.png differ diff --git a/images/titres/allemagne.png b/images/titres/allemagne.png new file mode 100644 index 0000000..0b97715 Binary files /dev/null and b/images/titres/allemagne.png differ diff --git a/images/titres/allemand.png b/images/titres/allemand.png new file mode 100644 index 0000000..cff4340 Binary files /dev/null and b/images/titres/allemand.png differ diff --git a/images/titres/aproposdusite.png b/images/titres/aproposdusite.png new file mode 100644 index 0000000..48b118b Binary files /dev/null and b/images/titres/aproposdusite.png differ diff --git a/images/titres/authentification.png b/images/titres/authentification.png new file mode 100644 index 0000000..ab789ce Binary files /dev/null and b/images/titres/authentification.png differ diff --git a/images/titres/avertissements.png b/images/titres/avertissements.png new file mode 100644 index 0000000..47b9fe0 Binary files /dev/null and b/images/titres/avertissements.png differ diff --git a/images/titres/bienvenue.png b/images/titres/bienvenue.png new file mode 100644 index 0000000..820c096 Binary files /dev/null and b/images/titres/bienvenue.png differ diff --git a/images/titres/bienvenueAlisson.png b/images/titres/bienvenueAlisson.png new file mode 100644 index 0000000..5d591f1 Binary files /dev/null and b/images/titres/bienvenueAlisson.png differ diff --git a/images/titres/bienvenueChristine.png b/images/titres/bienvenueChristine.png new file mode 100644 index 0000000..497df20 Binary files /dev/null and b/images/titres/bienvenueChristine.png differ diff --git a/images/titres/bienvenueFlorence.png b/images/titres/bienvenueFlorence.png new file mode 100644 index 0000000..3cf339c Binary files /dev/null and b/images/titres/bienvenueFlorence.png differ diff --git a/images/titres/bienvenueFlorent.png b/images/titres/bienvenueFlorent.png new file mode 100644 index 0000000..aa88da9 Binary files /dev/null and b/images/titres/bienvenueFlorent.png differ diff --git a/images/titres/bienvenuePierreO.png b/images/titres/bienvenuePierreO.png new file mode 100644 index 0000000..c7ddc10 Binary files /dev/null and b/images/titres/bienvenuePierreO.png differ diff --git a/images/titres/bienvenueRaphael.png b/images/titres/bienvenueRaphael.png new file mode 100644 index 0000000..7f4cdaa Binary files /dev/null and b/images/titres/bienvenueRaphael.png differ diff --git a/images/titres/bienvenueSerge.png b/images/titres/bienvenueSerge.png new file mode 100644 index 0000000..c06ef5a Binary files /dev/null and b/images/titres/bienvenueSerge.png differ diff --git a/images/titres/boitedenvoi.png b/images/titres/boitedenvoi.png new file mode 100644 index 0000000..b05974e Binary files /dev/null and b/images/titres/boitedenvoi.png differ diff --git a/images/titres/boitedereception.png b/images/titres/boitedereception.png new file mode 100644 index 0000000..e836281 Binary files /dev/null and b/images/titres/boitedereception.png differ diff --git a/images/titres/brouillons.png b/images/titres/brouillons.png new file mode 100644 index 0000000..340a5d1 Binary files /dev/null and b/images/titres/brouillons.png differ diff --git a/images/titres/centrelabappli.png b/images/titres/centrelabappli.png new file mode 100644 index 0000000..c2031da Binary files /dev/null and b/images/titres/centrelabappli.png differ diff --git a/images/titres/chat.png b/images/titres/chat.png new file mode 100644 index 0000000..c3acf68 Binary files /dev/null and b/images/titres/chat.png differ diff --git a/images/titres/cluedo.png b/images/titres/cluedo.png new file mode 100644 index 0000000..de515d5 Binary files /dev/null and b/images/titres/cluedo.png differ diff --git a/images/titres/commande.png b/images/titres/commande.png new file mode 100644 index 0000000..83f4a0c Binary files /dev/null and b/images/titres/commande.png differ diff --git a/images/titres/contact.png b/images/titres/contact.png new file mode 100644 index 0000000..b034f4c Binary files /dev/null and b/images/titres/contact.png differ diff --git a/images/titres/deutschland.png b/images/titres/deutschland.png new file mode 100644 index 0000000..0363db0 Binary files /dev/null and b/images/titres/deutschland.png differ diff --git a/images/titres/developpement.png b/images/titres/developpement.png new file mode 100644 index 0000000..87bb5bd Binary files /dev/null and b/images/titres/developpement.png differ diff --git a/images/titres/developpements.png b/images/titres/developpements.png new file mode 100644 index 0000000..ebd9fa6 Binary files /dev/null and b/images/titres/developpements.png differ diff --git a/images/titres/download.png b/images/titres/download.png new file mode 100644 index 0000000..3fac32e Binary files /dev/null and b/images/titres/download.png differ diff --git a/images/titres/downloads.png b/images/titres/downloads.png new file mode 100644 index 0000000..32c1a73 Binary files /dev/null and b/images/titres/downloads.png differ diff --git a/images/titres/drafts.png b/images/titres/drafts.png new file mode 100644 index 0000000..76c6190 Binary files /dev/null and b/images/titres/drafts.png differ diff --git a/images/titres/england.png b/images/titres/england.png new file mode 100644 index 0000000..bd9fa67 Binary files /dev/null and b/images/titres/england.png differ diff --git a/images/titres/etatsunis.png b/images/titres/etatsunis.png new file mode 100644 index 0000000..b861ad3 Binary files /dev/null and b/images/titres/etatsunis.png differ diff --git a/images/titres/feed.png b/images/titres/feed.png new file mode 100644 index 0000000..820b35e Binary files /dev/null and b/images/titres/feed.png differ diff --git a/images/titres/fluxrss.png b/images/titres/fluxrss.png new file mode 100644 index 0000000..551842c Binary files /dev/null and b/images/titres/fluxrss.png differ diff --git a/images/titres/foireauxquestions.png b/images/titres/foireauxquestions.png new file mode 100644 index 0000000..78645b9 Binary files /dev/null and b/images/titres/foireauxquestions.png differ diff --git a/images/titres/forum.png b/images/titres/forum.png new file mode 100644 index 0000000..5eca481 Binary files /dev/null and b/images/titres/forum.png differ diff --git a/images/titres/france.png b/images/titres/france.png new file mode 100644 index 0000000..779b995 Binary files /dev/null and b/images/titres/france.png differ diff --git a/images/titres/gerersamusique.png b/images/titres/gerersamusique.png new file mode 100644 index 0000000..e92031c Binary files /dev/null and b/images/titres/gerersamusique.png differ diff --git a/images/titres/gerersesporteclefs.png b/images/titres/gerersesporteclefs.png new file mode 100644 index 0000000..e7c6548 Binary files /dev/null and b/images/titres/gerersesporteclefs.png differ diff --git a/images/titres/germany.png b/images/titres/germany.png new file mode 100644 index 0000000..c5bf076 Binary files /dev/null and b/images/titres/germany.png differ diff --git a/images/titres/histoire.png b/images/titres/histoire.png new file mode 100644 index 0000000..3a55f66 Binary files /dev/null and b/images/titres/histoire.png differ diff --git a/images/titres/history.png b/images/titres/history.png new file mode 100644 index 0000000..9b3f4fd Binary files /dev/null and b/images/titres/history.png differ diff --git a/images/titres/home.png b/images/titres/home.png new file mode 100644 index 0000000..0b5ca05 Binary files /dev/null and b/images/titres/home.png differ diff --git a/images/titres/homepage.png b/images/titres/homepage.png new file mode 100644 index 0000000..6fcda6d Binary files /dev/null and b/images/titres/homepage.png differ diff --git a/images/titres/identification.png b/images/titres/identification.png new file mode 100644 index 0000000..b65a0b8 Binary files /dev/null and b/images/titres/identification.png differ diff --git a/images/titres/inscription.png b/images/titres/inscription.png new file mode 100644 index 0000000..57010e3 Binary files /dev/null and b/images/titres/inscription.png differ diff --git a/images/titres/jeuxenligne.png b/images/titres/jeuxenligne.png new file mode 100644 index 0000000..8042baf Binary files /dev/null and b/images/titres/jeuxenligne.png differ diff --git a/images/titres/journal.png b/images/titres/journal.png new file mode 100644 index 0000000..5243314 Binary files /dev/null and b/images/titres/journal.png differ diff --git a/images/titres/labapplicenter.png b/images/titres/labapplicenter.png new file mode 100644 index 0000000..566aeb9 Binary files /dev/null and b/images/titres/labapplicenter.png differ diff --git a/images/titres/lastdevelopments.png b/images/titres/lastdevelopments.png new file mode 100644 index 0000000..b1a8d41 Binary files /dev/null and b/images/titres/lastdevelopments.png differ diff --git a/images/titres/login.png b/images/titres/login.png new file mode 100644 index 0000000..0dbe342 Binary files /dev/null and b/images/titres/login.png differ diff --git a/images/titres/messagerie.png b/images/titres/messagerie.png new file mode 100644 index 0000000..3eb0ec5 Binary files /dev/null and b/images/titres/messagerie.png differ diff --git a/images/titres/news.png b/images/titres/news.png new file mode 100644 index 0000000..72d43a4 Binary files /dev/null and b/images/titres/news.png differ diff --git a/images/titres/newspaper.png b/images/titres/newspaper.png new file mode 100644 index 0000000..ce949ac Binary files /dev/null and b/images/titres/newspaper.png differ diff --git a/images/titres/nouveautes.png b/images/titres/nouveautes.png new file mode 100644 index 0000000..104fa29 Binary files /dev/null and b/images/titres/nouveautes.png differ diff --git a/images/titres/onlinegames.png b/images/titres/onlinegames.png new file mode 100644 index 0000000..95ad670 Binary files /dev/null and b/images/titres/onlinegames.png differ diff --git a/images/titres/pagededemarrage.png b/images/titres/pagededemarrage.png new file mode 100644 index 0000000..fccc788 Binary files /dev/null and b/images/titres/pagededemarrage.png differ diff --git a/images/titres/paiement.png b/images/titres/paiement.png new file mode 100644 index 0000000..b913860 Binary files /dev/null and b/images/titres/paiement.png differ diff --git a/images/titres/parametres.png b/images/titres/parametres.png new file mode 100644 index 0000000..f06f5a9 Binary files /dev/null and b/images/titres/parametres.png differ diff --git a/images/titres/partage.png b/images/titres/partage.png new file mode 100644 index 0000000..5e26e26 Binary files /dev/null and b/images/titres/partage.png differ diff --git a/images/titres/partenaires.png b/images/titres/partenaires.png new file mode 100644 index 0000000..795e10a Binary files /dev/null and b/images/titres/partenaires.png differ diff --git a/images/titres/pochettescd.png b/images/titres/pochettescd.png new file mode 100644 index 0000000..df52b4e Binary files /dev/null and b/images/titres/pochettescd.png differ diff --git a/images/titres/pommail.png b/images/titres/pommail.png new file mode 100644 index 0000000..0ad79f4 Binary files /dev/null and b/images/titres/pommail.png differ diff --git a/images/titres/popmail.png b/images/titres/popmail.png new file mode 100644 index 0000000..943e785 Binary files /dev/null and b/images/titres/popmail.png differ diff --git a/images/titres/products.png b/images/titres/products.png new file mode 100644 index 0000000..9326947 Binary files /dev/null and b/images/titres/products.png differ diff --git a/images/titres/produits.png b/images/titres/produits.png new file mode 100644 index 0000000..e268124 Binary files /dev/null and b/images/titres/produits.png differ diff --git a/images/titres/professionnel.png b/images/titres/professionnel.png new file mode 100644 index 0000000..1598d3a Binary files /dev/null and b/images/titres/professionnel.png differ diff --git a/images/titres/professionnels.png b/images/titres/professionnels.png new file mode 100644 index 0000000..70abe4a Binary files /dev/null and b/images/titres/professionnels.png differ diff --git a/images/titres/proffessionnal.png b/images/titres/proffessionnal.png new file mode 100644 index 0000000..677761c Binary files /dev/null and b/images/titres/proffessionnal.png differ diff --git a/images/titres/programmation.png b/images/titres/programmation.png new file mode 100644 index 0000000..f649129 Binary files /dev/null and b/images/titres/programmation.png differ diff --git a/images/titres/projects.png b/images/titres/projects.png new file mode 100644 index 0000000..902580a Binary files /dev/null and b/images/titres/projects.png differ diff --git a/images/titres/projets.png b/images/titres/projets.png new file mode 100644 index 0000000..88aac95 Binary files /dev/null and b/images/titres/projets.png differ diff --git a/images/titres/realisations.png b/images/titres/realisations.png new file mode 100644 index 0000000..f4d89fb Binary files /dev/null and b/images/titres/realisations.png differ diff --git a/images/titres/recherche.png b/images/titres/recherche.png new file mode 100644 index 0000000..9b084c7 Binary files /dev/null and b/images/titres/recherche.png differ diff --git a/images/titres/register.png b/images/titres/register.png new file mode 100644 index 0000000..6010b08 Binary files /dev/null and b/images/titres/register.png differ diff --git a/images/titres/reglages.png b/images/titres/reglages.png new file mode 100644 index 0000000..6eb498d Binary files /dev/null and b/images/titres/reglages.png differ diff --git a/images/titres/royaumeuni.png b/images/titres/royaumeuni.png new file mode 100644 index 0000000..8ee989b Binary files /dev/null and b/images/titres/royaumeuni.png differ diff --git a/images/titres/search.png b/images/titres/search.png new file mode 100644 index 0000000..16fb143 Binary files /dev/null and b/images/titres/search.png differ diff --git a/images/titres/selection.png b/images/titres/selection.png new file mode 100644 index 0000000..85d404c Binary files /dev/null and b/images/titres/selection.png differ diff --git a/images/titres/selectiondumois.png b/images/titres/selectiondumois.png new file mode 100644 index 0000000..2dd1bfa Binary files /dev/null and b/images/titres/selectiondumois.png differ diff --git a/images/titres/selectiondumoment.png b/images/titres/selectiondumoment.png new file mode 100644 index 0000000..52bb8c5 Binary files /dev/null and b/images/titres/selectiondumoment.png differ diff --git a/images/titres/services.png b/images/titres/services.png new file mode 100644 index 0000000..9eb1838 Binary files /dev/null and b/images/titres/services.png differ diff --git a/images/titres/settings.png b/images/titres/settings.png new file mode 100644 index 0000000..922e94a Binary files /dev/null and b/images/titres/settings.png differ diff --git a/images/titres/subscription.png b/images/titres/subscription.png new file mode 100644 index 0000000..d7ded22 Binary files /dev/null and b/images/titres/subscription.png differ diff --git a/images/titres/sudoku.png b/images/titres/sudoku.png new file mode 100644 index 0000000..5e64b91 Binary files /dev/null and b/images/titres/sudoku.png differ diff --git a/images/titres/sudokumania.png b/images/titres/sudokumania.png new file mode 100644 index 0000000..51a4994 Binary files /dev/null and b/images/titres/sudokumania.png differ diff --git a/images/titres/support technique.png b/images/titres/support technique.png new file mode 100644 index 0000000..3f84bf9 Binary files /dev/null and b/images/titres/support technique.png differ diff --git a/images/titres/telechargement.png b/images/titres/telechargement.png new file mode 100644 index 0000000..b53f5fd Binary files /dev/null and b/images/titres/telechargement.png differ diff --git a/images/titres/telechargements.png b/images/titres/telechargements.png new file mode 100644 index 0000000..a7bcb35 Binary files /dev/null and b/images/titres/telechargements.png differ diff --git a/images/titres/toptelechargements.png b/images/titres/toptelechargements.png new file mode 100644 index 0000000..e2ef01c Binary files /dev/null and b/images/titres/toptelechargements.png differ diff --git a/images/titres/touchecoule.png b/images/titres/touchecoule.png new file mode 100644 index 0000000..83dcc21 Binary files /dev/null and b/images/titres/touchecoule.png differ diff --git a/images/titres/transfert.png b/images/titres/transfert.png new file mode 100644 index 0000000..edc4d28 Binary files /dev/null and b/images/titres/transfert.png differ diff --git a/images/titres/transferts.png b/images/titres/transferts.png new file mode 100644 index 0000000..b09b8a6 Binary files /dev/null and b/images/titres/transferts.png differ diff --git a/images/titres/upload.png b/images/titres/upload.png new file mode 100644 index 0000000..a503d48 Binary files /dev/null and b/images/titres/upload.png differ diff --git a/images/titres/users.png b/images/titres/users.png new file mode 100644 index 0000000..2b8796a Binary files /dev/null and b/images/titres/users.png differ diff --git a/images/titres/utilisateurs.png b/images/titres/utilisateurs.png new file mode 100644 index 0000000..3c46731 Binary files /dev/null and b/images/titres/utilisateurs.png differ diff --git a/images/titres/warnings.png b/images/titres/warnings.png new file mode 100644 index 0000000..17cecaa Binary files /dev/null and b/images/titres/warnings.png differ diff --git a/images/titres/welcome.png b/images/titres/welcome.png new file mode 100644 index 0000000..2c4f19a Binary files /dev/null and b/images/titres/welcome.png differ diff --git a/images/titres/willkommen.png b/images/titres/willkommen.png new file mode 100644 index 0000000..062225b Binary files /dev/null and b/images/titres/willkommen.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..48da792 --- /dev/null +++ b/index.html @@ -0,0 +1,31 @@ + + + + .: Pommultimédia 4 home :. + + + + + + + + + + + +
Menu
+ + +
+

Bienvenue sur le serveur Pommultimédia for home !

+ +
+
Détection du JavaScript ...
+ + \ No newline at end of file diff --git a/js/ajax.js b/js/ajax.js new file mode 100644 index 0000000..6da45b8 --- /dev/null +++ b/js/ajax.js @@ -0,0 +1,196 @@ +var URL_SERVEUR = 'http://hsc.escrime.local/'; //URL du serveur +var last_position_bandeau = true; //Dernière position du bandeau définie par l'utilisateur +var fade_objects = {loading: {statut: -1, timer: false}, secondBody: {statut: -1, timer: false}}; +var ajax_save_html = false; +var ajax_save_json = false; +var ajax_time_sauve = false; + +function loadPage(url) + { + $('secondBody').className = document.getElementsByTagName("body").item(0).className; + decomp = url.split("?"); + start_fadeIn('loading'); + start_fadeIn('secondBody'); + if (decomp.length >= 2) { + new Ajax.Request( + 'ajax.php', + { + method: 'post', + parameters: {url: decomp[1]}, + onSuccess: onSuccess_ajax, + onFailure: function() { loadPage("ici?p=accueil"); alert('Une erreur s\'est produite lors du téléchargement de la page !'); } + } + ); + hideShownMenu(); + return false; + } + + ajax_time_sauve = setTimeout("rescue", 15000); + } + +function onSuccess_ajax(transport, json) + { + ajax_save_html = transport.responseText; + if (json != null) + ajax_save_json = json; + else + ajax_save_json = false + printPage(); + } + +function printPage() + { + if (fade_objects["secondBody"]["statut"] != 1) + setTimeout("printPage()", 500); + else + { + $('contenu').innerHTML = ajax_save_html; + verifLinks(); + if (ajax_save_json != false) + { + document.getElementsByTagName("body").item(0).className = ajax_save_json.class; + if (ajax_save_json.bandeau && (document.getElementById('submenuContainer').style.top == "221px" || document.getElementById('submenuContainer').style.top == "220px")) + ajax_hideBandeau(); + else if (document.getElementById('submenuContainer').style.top == "51px" && last_position_bandeau && !ajax_save_json.bandeau) + ajax_showBandeau(); + + if (ajax_save_json.special == "resultats") + load_pageResultats(); + else if (ajax_save_json.special == "maps") + { + var map = new GMap2(document.getElementById('map')); + initMap(); + } + } + + start_fadeOut('loading'); + start_fadeOut('secondBody'); + + } + } + +function verifLinks() + { + totalLiens = document.getElementsByTagName("a"); + for (var i=0 ; i < totalLiens.length ; i++) + { + //TODO tester si le lien appartient au serveur, s'il n'y appartient pas, on laisse le lien en normal + if (!document.getElementsByTagName("a").item(i).onclick) { + document.getElementsByTagName("a").item(i).onclick = function onclick(event) + { + loadPage(this.href); + return false; + }; + } + } + } + +function ajax_hideBandeau() + { + ajax_rec_hideBandeau(0); + } + +function ajax_rec_hideBandeau(pos) + { + pos = pos + 15; + if (pos > 169) pos = 170; + modifyBandeau(pos); + if (pos <= 169) setTimeout('ajax_rec_hideBandeau(' + pos + ')', 0); + } + + +function ajax_showBandeau() + { + ajax_rec_showBandeau(170); + } + +function ajax_rec_showBandeau(pos) + { + pos = pos - 15; + if (pos < 0) pos = 0; + modifyBandeau(pos); + if (pos > 0) setTimeout('ajax_rec_showBandeau(' + pos + ')', 0); + } + +function load_pageResultats() + { + initAutoCompleter(); + $('formResultats').onsubmit = function onsubmit(event) + { + $('secondBody').className = document.getElementsByTagName("body").item(0).className; + start_fadeIn('loading'); + start_fadeIn('secondBody'); + new Ajax.Request( + 'ajax.php', + { + method: 'post', + parameters: {url: "p=resultats", nom: $('nomtireur').value}, + onSuccess: onSuccess_ajax, + onFailure: function() { alert('Failure !'); } + } + ); + return false; + }; + } + +function start_fadeIn(id) + { + if (fade_objects[id]["statut"] == 0) + fade_objects[id]["timer"] = setTimeout("start_fadeIn(" + id + ")", 500); + else if (fade_objects[id]["statut"] != 1) + { + changeOpac(0, id); + document.getElementById(id).style.display = "block"; + fade_objects[id]["statut"] = 0; + + fadeIn(0, id); + } + } + +function start_fadeOut(id) + { + if (fade_objects[id]["statut"] == 0) + fade_objects[id]["timer"] = setTimeout("start_fadeOut(" + id + ")", 500); + else if (fade_objects[id]["statut"] != -1) + { + changeOpac(100, id); + document.getElementById(id).style.display = "block"; + fade_objects[id]["statut"] = 0; + + fadeOut(10, id); + } + } + +function fadeIn(i, id) + { + i++; + changeOpac(i*10, id); + + if (i < 10) + setTimeout("fadeIn(" + i + ", '" + id + "')", 30); + else + fade_objects[id]["statut"] = 1; + } + +function fadeOut(i, id) + { + i--; + changeOpac(i*10, id); + + if (i > 0) + setTimeout("fadeOut(" + i + ", '" + id + "')", 30); + else + { + document.getElementById(id).style.display = "none"; + fade_objects[id]["statut"] = -1; + } + } + +function changeOpac(opacity, id) { + if (opacity > 100) opacity = 100; + var object = document.getElementById(id).style; + object.opacity = (opacity / 100); + object.MozOpacity = (opacity / 100); + object.KhtmlOpacity = (opacity / 100); + object.filter = "alpha(opacity=" + opacity + ")"; +} \ No newline at end of file diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..5507557 --- /dev/null +++ b/js/app.js @@ -0,0 +1,247 @@ +function Application(XMLproperties) +{ + this.name = XMLproperties.getElementsByTagName("name")[0].firstChild.data; + this.dir = XMLproperties.getElementsByTagName("dir")[0].firstChild.data; + + if (XMLproperties.getElementsByTagName("description")[0]) + this.description = XMLproperties.getElementsByTagName("description")[0].firstChild.data; + else + this.description = null; + + this.etatAvancement = XMLproperties.getElementsByTagName("etatAvancement")[0].firstChild.data; + this.version = XMLproperties.getElementsByTagName("version")[0].firstChild.data; + + if (XMLproperties.getElementsByTagName("lang")[0]) + this.lang = XMLproperties.getElementsByTagName("lang")[0].firstChild.data; + else + this.lang = null; + + if (XMLproperties.getElementsByTagName("developpeur")[0]) + this.developpeur = XMLproperties.getElementsByTagName("developpeur")[0].firstChild.data; + else + this.developpeur = null; + + if (XMLproperties.getElementsByTagName("corps")[0]) + this.corps = XMLproperties.getElementsByTagName("corps")[0].firstChild.data; + else + this.corps = "corps"; + + this.menu = null; +} + +Application.prototype.getHomeElt = function() +{ + var app = document.createElement("dl"); + app.className = "application " + this.etatAvancement; + + var appTitle = document.createElement("dt"); + appTitle.innerHTML = this.name; + var appDescription = document.createElement("dd"); + appDescription.innerHTML = this.description; + + app.observe('click', this.load.bind(this)); + + app.appendChild(appTitle); + app.appendChild(appDescription); + + return app; +} + +Application.prototype.load = function() +{ + printEtat(6); + var test = new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "display", a: this.dir}, + onSuccess: this.loaded.bind(this), + onFailure: function() { printEtat(3); } + } + ); +} + +Application.prototype.loaded = function(transport, json) +{ + clearScreen(); + + var display = transport.responseXML.documentElement.getElementsByTagName("display")[0]; + var property = transport.responseXML.documentElement.getElementsByTagName("property")[0]; + + if (display.getElementsByTagName("titre")[0]) + $('titre').src = imgTitres_dir + display.getElementsByTagName("titre")[0].firstChild.data; + + if (display.getElementsByTagName("css")) + { + //On supprime le style par défaut + if ($("main_thm")) + document.getElementsByTagName('head')[0].removeChild($("main_thm")); + + var styles = display.getElementsByTagName("css"); + for (i = styles.length - 1; i >= 0; i--) + { + var css_file = document.createElement("link"); + css_file.type = 'text/css'; + css_file.rel = 'stylesheet'; + css_file.className = 'app'; + if (styles[i].getAttribute("media")) + css_file.media = styles[i].getAttribute("media"); + css_file.href = "applications/" + this.dir + "/" + styles[i].firstChild.data; + + document.getElementsByTagName('head')[0].appendChild(css_file); + } + } + + if (display.getElementsByTagName("script")) + { + var scripts = display.getElementsByTagName("script"); + for (i = scripts.length - 1; i >= 0; i--) + { + js_file = document.createElement("script"); + js_file.type = 'text/javascript'; + js_file.className = 'app'; + js_file.src = "applications/" + this.dir + "/" + scripts[i].firstChild.data; + js_file.defer = true; + + document.getElementsByTagName('head')[0].appendChild(js_file); + } + } + + if (display.getElementsByTagName("background").length > 0) + $('body').style.backgroundImage = "url(" + display.getElementsByTagName("background")[0].firstChild.data + ")"; + + var etat; + if (property.getElementsByTagName("etatAvancement").length > 0) + etat = property.getElementsByTagName("etatAvancement")[0].firstChild.data; + else + etat = ""; + + if (etat == "En construction" || etat == "en construction" || etat == "enconstruction" || etat == "construction" || etat == "c") + $('etatAvance').src = "images/etats/construction.png"; + else if (etat == "Alpha" || etat == "alpha" || etat == "a") + $('etatAvance').src = "images/etats/alpha.png"; + else if (etat == "Beta" || etat == "beta" || etat == "Béta" || etat == "béta" || etat == "b") + $('etatAvance').src = "images/etats/beta.png"; + else + $('etatAvance').src = "images/etats/final.png"; + + //On affiche la page + if (display.getElementsByTagName('body')[0]) + $('corps').innerHTML = display.getElementsByTagName('body')[0].firstChild.data; + + //On prépare le menu + if (property.getElementsByTagName("menu").length > 0) + this.menu = eval(property.getElementsByTagName("menu")[0].firstChild.data); + this.genMenu(username != ""); + + //On lance l'application + if (display.getElementsByTagName("js")[0]) + { + var scripts = display.getElementsByTagName("js"); + for (i = scripts.length - 1; i >= 0; i--) + eval(scripts[i].firstChild.data); + + runApplication(property, display, json); + } + else + setTimeout("runApplication" + this.dir + "(" + property + ", " + display + ", " + json + ");", 1); +// setTimeout("alert('test')", 0); + + printEtat(0); +} + +Application.prototype.genMenu = function(online) +{ + //On supprime tous les éléments du menu actuel + clearNode($('menu')); + + //On ajoute le titre + var item = document.createElement("li"); + item.innerHTML = this.name; + item.id = "nameApp"; + $('menu').appendChild(item); + + //Lien vers la page d'accueil + var item = document.createElement("li"); + item.onclick = function() { hideShownMenu(); firstLoad(); }; + item.innerHTML = "Accueil"; + if (online) + item.className = "item"; + else + item.className = "item hr"; + $('menu').appendChild(item); + + //Lien de déconnexion + if (online) + { + var item = document.createElement("li"); + item.onclick = function() { hideShownMenu(); deconnexion(); }; + item.innerHTML = "Déconnexion"; + item.className = "item hr"; + $('menu').appendChild(item); + } + + //On insère les éléments de l'app + if (this.menu) + { + for (var i = this.menu.length - 1; i >= 0; i--) + addMenuItem(this.menu[i]["text"], this.menu[i]["eventClick"]); + } + + //On insère le about app + var item = document.createElement("li"); + item.observe('click', this.about.bind(this)); + item.innerHTML = "À propos de ..."; + item.className = "item hr"; + $('menu').appendChild(item); + + //Lien vers la page à propos du site + var item = document.createElement("li"); + item.onclick = function() { hideShownMenu(); loadPage('aproposdusite'); }; + item.innerHTML = "À propos du site"; + item.className = "item"; + $('menu').appendChild(item); +} + +Application.prototype.about = function() +{ + hideShownMenu(); + $(this.corps).innerHTML = ""; + + //Texte correspondant à l'état de l'app + var txtEtat = ""; + if (this.etatAvancement == "En construction" || this.etatAvancement == "en construction" || this.etatAvancement == "enconstruction" || this.etatAvancement == "construction" || this.etatAvancement == "c") + txtEtat = "En construction"; + else if (this.etatAvancement == "Béta" || this.etatAvancement == "Beta" || this.etatAvancement == "beta" || this.etatAvancement == "béta" || this.etatAvancement == "b") + txtEtat = "Béta"; + else if (this.etatAvancement == "Alpha" || this.etatAvancement == "alpha" || this.etatAvancement == "a") + txtEtat = "Alpha"; + + var titre = document.createElement("h2"); + titre.innerHTML = "A propos de " + this.name + " pour Pommultimedia for Home"; + $(this.corps).appendChild(titre); + titre = document.createElement("h3"); + titre.innerHTML = this.name + "
Version " + this.version + " " + txtEtat; + $(this.corps).appendChild(titre); + if (this.description != null) + { + titre = document.createElement("h4"); + titre.innerHTML = "Description : " + this.description; + $(this.corps).appendChild(titre); + } + if (this.lang != null) + { + titre = document.createElement("h4"); + titre.innerHTML = "Langue : " + this.lang; + $(this.corps).appendChild(titre); + } + titre = document.createElement("h4"); + titre.innerHTML = "Nom court : " + this.dir; + $(this.corps).appendChild(titre); + if (this.developpeur != null) + { + titre = document.createElement("h4"); + titre.innerHTML = "Développeur : " + this.developpeur; + $(this.corps).appendChild(titre); + } +} \ No newline at end of file diff --git a/js/pa4h.js b/js/pa4h.js new file mode 100644 index 0000000..bca7954 --- /dev/null +++ b/js/pa4h.js @@ -0,0 +1,298 @@ +var imgTitres_dir = "images/titres/"; +var username = ""; +var apps = Array(); + +function clearNode(node) +{ + if (node.hasChildNodes()) + { + while (node.childNodes.length >= 1) + node.removeChild(node.firstChild); + } +} + +window.onload = function() +{ + printEtat(1); + clearScreen(); + firstLoad(); + + document.getElementById('btMenu').onclick = function(){ + showMenu(); + } + document.getElementById('btMenu').onmouseout = function(){ + setHideMenuTimeout(); + } + document.getElementById('menu').onmouseover = function(){ + showMenu(); + } + document.getElementById('menu').onmouseout = function(){ + setHideMenuTimeout(); + } +} + +function firstLoad() +{ + new Ajax.Request( + 'ajax.php', + { + onSuccess: function(transport, json) + { + printEtat(2); + if (json.statut == 1) + { + username = json.username; + + if (window.sessionStorage && window.sessionStorage.username == username) + { + //On restaure l'application en cours + + } + else + page_accueil(); + } + else + loadPage("connexion"); + printEtat(0); + }, + onFailure: function() { printEtat(3); } + } + ); +} + +function deconnexion() +{ + printEtat(1); + clearScreen(); + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "logout"}, + onSuccess: function(transport, json) { firstLoad(); }, + onFailure: function() { printEtat(3); } + } + ); +} + +function printEtat(id) +{ + if (id == 0) + $('etat').innerHTML = ""; + else if (id == 1) + $('etat').innerHTML = "Connexion au serveur en cours ..."; + else if (id == 2) + $('etat').innerHTML = "Connexion établie, affichage de la page ..."; + else if (id == 3) + $('etat').innerHTML = "Impossible de contacter le serveur, délais d'attente expiré !"; + else if (id == 4) + $('etat').innerHTML = "Vérification des informations en cours ..."; + else if (id == 5) + $('etat').innerHTML = "Récupération de la liste des applications ..."; + else if (id == 6) + $('etat').innerHTML = "Chargement de l'application ..."; + else + $('etat').innerHTML = "État inconnu : #" + id; +} + +function clearScreen() +{ + if ($('logo').style.display != "block") + $('logo').style.display = "block"; + + genMenu(username != ""); + $('corps').innerHTML = ""; + + $('etatAvance').src = "images/etats/alpha.png"; + + var head = document.getElementsByTagName("head")[0]; + //On décharge les fichiers JavaScript non standards + if (head.getElementsByTagName("script")[4]) + { + var scripts = head.getElementsByTagName("script"); + for (i = scripts.length - 1; i >= 0; i--) + { + if (scripts[i].className == "app") + head.removeChild(scripts[i]); + } + } + + //Idem avec les fichiers CSS + if (head.getElementsByTagName("link")[3]) + { + var links = head.getElementsByTagName("link"); + for (i = links.length - 1; i >= 0; i--) + { + if (links[i].className == "app") + head.removeChild(links[i]); + } + } + + //On ajoute le thème par défaut + if (!$("main_thm")) + { + var css_file = document.createElement("link"); + css_file.type = 'text/css'; + css_file.rel = 'stylesheet'; + css_file.media = 'all'; + css_file.id = 'main_thm'; + css_file.href = "style.css"; + document.getElementsByTagName('head')[0].appendChild(css_file); + } +} + +function genMenu(online) +{ + //On supprime tous les éléments du menu + clearNode($('menu')); + + //On ajoute le titre + var item = document.createElement("li"); + item.innerHTML = "PA4home"; + item.id = "nameApp"; + $('menu').appendChild(item); + + //Lien vers la page d'accueil + item = document.createElement("li"); + item.onclick = function() { hideShownMenu(); firstLoad(); }; + item.innerHTML = "Accueil"; + if (online) + item.className = "item"; + else + item.className = "item hr"; + $('menu').appendChild(item); + + //Lien de déconnexion + if (online) + { + item = document.createElement("li"); + item.onclick = function() { hideShownMenu(); deconnexion(); }; + item.innerHTML = "Déconnexion"; + item.className = "item hr"; + $('menu').appendChild(item); + } + + //Lien vers la page à propos du site + item = document.createElement("li"); + item.onclick = function() { hideShownMenu(); loadPage('aproposdusite'); }; + item.innerHTML = "À propos du site"; + item.className = "item"; + $('menu').appendChild(item); +} + +function addMenuItem(text, iven) +{ + var item = document.createElement("li"); + item.onclick = function(e) { + hideShownMenu(); + eval(iven); + }; + item.innerHTML = text; + item.className = "item"; + $('menu').appendChild(item); +} + +/************************************** + * Partie contenant les pages du site * + **************************************/ + +function loadPage(nom) +{ + clearScreen(); + printEtat(1); + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "page", p: nom}, + onSuccess: function(transport, json) + { + printEtat(2); + $('titre').src = imgTitres_dir + transport.responseXML.documentElement.getElementsByTagName("titre")[0].firstChild.data; + $('corps').innerHTML = transport.responseXML.documentElement.getElementsByTagName("body")[0].firstChild.data; + + if (transport.responseXML.documentElement.getElementsByTagName("js")) + { + var scripts = transport.responseXML.documentElement.getElementsByTagName("js"); + var nbScripts = scripts.length; + for (i = 0; i < nbScripts; i++) + eval(scripts[i].firstChild.data); + } + + printEtat(0); + }, + onFailure: function() { printEtat(3); } + } + ); +} + +function page_accueil() +{ + clearScreen(); + printEtat(5); + + if (username == "root" || username == "pierre-o") + $('titre').src = imgTitres_dir + "bienvenuePierreO.png"; + else if (username == "sergcaen" || username == "serge") + $('titre').src = imgTitres_dir + "bienvenueSerge.png"; + else if (username == "christine" || username == "chriscaen") + $('titre').src = imgTitres_dir + "bienvenueChristine.png"; + else if (username == "raphael" || username == "minou") + $('titre').src = imgTitres_dir + "bienvenueRaphael.png"; + else if (username == "florence" || username == "floflo") + $('titre').src = imgTitres_dir + "bienvenueFlorence.png"; + else if (username == "florent") + $('titre').src = imgTitres_dir + "bienvenueFlorent.png"; + else if (username == "alisson13081991" || username == "alisson13081991@hotmail.fr") + $('titre').src = imgTitres_dir + "bienvenueAlisson.png"; + else + $('titre').src = imgTitres_dir + "bienvenue.png"; + + new Ajax.Request( + 'ajax.php', + { + method: 'get', + parameters: {d: "accueil"}, + onSuccess: function(transport, json) + { + var applications = transport.responseXML.documentElement.getElementsByTagName("application"); + for (i = applications.length - 1; i >= 0; i--) + { + var app = new Application(applications[i]); + apps.pop(app); + + var elt = app.getHomeElt(); + + $('corps').appendChild(elt); + } + printEtat(0); + }, + onFailure: function() { printEtat(3); } + } + ); +} + +function runApplication(property, display, json){ + alert("Aucun lancement à faire !"); +} + +//Menu +var menu_timeout; + +function showMenu() +{ + if (menu_timeout) + clearTimeout(menu_timeout); + + $('menu').style.display = "block"; +} + +function setHideMenuTimeout() +{ + menu_timeout = setTimeout('hideShownMenu()', 500); +} + +function hideShownMenu() +{ + $('menu').style.display = "none"; +} \ No newline at end of file diff --git a/js/prototype.js b/js/prototype.js new file mode 100644 index 0000000..474b223 --- /dev/null +++ b/js/prototype.js @@ -0,0 +1,6082 @@ +/* Prototype JavaScript framework, version 1.7 + * (c) 2005-2010 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + + Version: '1.7', + + Browser: (function(){ + var ua = navigator.userAgent; + var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; + return { + IE: !!window.attachEvent && !isOpera, + Opera: isOpera, + WebKit: ua.indexOf('AppleWebKit/') > -1, + Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, + MobileSafari: /Apple.*Mobile/.test(ua) + } + })(), + + BrowserFeatures: { + XPath: !!document.evaluate, + + SelectorsAPI: !!document.querySelector, + + ElementExtensions: (function() { + var constructor = window.Element || window.HTMLElement; + return !!(constructor && constructor.prototype); + })(), + SpecificElementExtensions: (function() { + if (typeof window.HTMLDivElement !== 'undefined') + return true; + + var div = document.createElement('div'), + form = document.createElement('form'), + isSupported = false; + + if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { + isSupported = true; + } + + div = form = null; + + return isSupported; + })() + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +var Abstract = { }; + + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +/* Based on Alex Arnell's inheritance implementation. */ + +var Class = (function() { + + var IS_DONTENUM_BUGGY = (function(){ + for (var p in { toString: 1 }) { + if (p === 'toString') return false; + } + return true; + })(); + + function subclass() {}; + function create() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0, length = properties.length; i < length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype, + properties = Object.keys(source); + + if (IS_DONTENUM_BUGGY) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames()[0] == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); +(function() { + + var _toString = Object.prototype.toString, + NULL_TYPE = 'Null', + UNDEFINED_TYPE = 'Undefined', + BOOLEAN_TYPE = 'Boolean', + NUMBER_TYPE = 'Number', + STRING_TYPE = 'String', + OBJECT_TYPE = 'Object', + FUNCTION_CLASS = '[object Function]', + BOOLEAN_CLASS = '[object Boolean]', + NUMBER_CLASS = '[object Number]', + STRING_CLASS = '[object String]', + ARRAY_CLASS = '[object Array]', + DATE_CLASS = '[object Date]', + NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && + typeof JSON.stringify === 'function' && + JSON.stringify(0) === '0' && + typeof JSON.stringify(Prototype.K) === 'undefined'; + + function Type(o) { + switch(o) { + case null: return NULL_TYPE; + case (void 0): return UNDEFINED_TYPE; + } + var type = typeof o; + switch(type) { + case 'boolean': return BOOLEAN_TYPE; + case 'number': return NUMBER_TYPE; + case 'string': return STRING_TYPE; + } + return OBJECT_TYPE; + } + + function extend(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; + } + + function inspect(object) { + try { + if (isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + } + + function toJSON(value) { + return Str('', { '': value }, []); + } + + function Str(key, holder, stack) { + var value = holder[key], + type = typeof value; + + if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + + var _class = _toString.call(value); + + switch (_class) { + case NUMBER_CLASS: + case BOOLEAN_CLASS: + case STRING_CLASS: + value = value.valueOf(); + } + + switch (value) { + case null: return 'null'; + case true: return 'true'; + case false: return 'false'; + } + + type = typeof value; + switch (type) { + case 'string': + return value.inspect(true); + case 'number': + return isFinite(value) ? String(value) : 'null'; + case 'object': + + for (var i = 0, length = stack.length; i < length; i++) { + if (stack[i] === value) { throw new TypeError(); } + } + stack.push(value); + + var partial = []; + if (_class === ARRAY_CLASS) { + for (var i = 0, length = value.length; i < length; i++) { + var str = Str(i, value, stack); + partial.push(typeof str === 'undefined' ? 'null' : str); + } + partial = '[' + partial.join(',') + ']'; + } else { + var keys = Object.keys(value); + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i], str = Str(key, value, stack); + if (typeof str !== "undefined") { + partial.push(key.inspect(true)+ ':' + str); + } + } + partial = '{' + partial.join(',') + '}'; + } + stack.pop(); + return partial; + } + } + + function stringify(object) { + return JSON.stringify(object); + } + + function toQueryString(object) { + return $H(object).toQueryString(); + } + + function toHTML(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + } + + function keys(object) { + if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } + var results = []; + for (var property in object) { + if (object.hasOwnProperty(property)) { + results.push(property); + } + } + return results; + } + + function values(object) { + var results = []; + for (var property in object) + results.push(object[property]); + return results; + } + + function clone(object) { + return extend({ }, object); + } + + function isElement(object) { + return !!(object && object.nodeType == 1); + } + + function isArray(object) { + return _toString.call(object) === ARRAY_CLASS; + } + + var hasNativeIsArray = (typeof Array.isArray == 'function') + && Array.isArray([]) && !Array.isArray({}); + + if (hasNativeIsArray) { + isArray = Array.isArray; + } + + function isHash(object) { + return object instanceof Hash; + } + + function isFunction(object) { + return _toString.call(object) === FUNCTION_CLASS; + } + + function isString(object) { + return _toString.call(object) === STRING_CLASS; + } + + function isNumber(object) { + return _toString.call(object) === NUMBER_CLASS; + } + + function isDate(object) { + return _toString.call(object) === DATE_CLASS; + } + + function isUndefined(object) { + return typeof object === "undefined"; + } + + extend(Object, { + extend: extend, + inspect: inspect, + toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, + toQueryString: toQueryString, + toHTML: toHTML, + keys: Object.keys || keys, + values: values, + clone: clone, + isElement: isElement, + isArray: isArray, + isHash: isHash, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isDate: isDate, + isUndefined: isUndefined + }); +})(); +Object.extend(Function.prototype, (function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + } + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + } + + function argumentNames() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + } + + function bind(context) { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + + function bindAsEventListener(context) { + var __method = this, args = slice.call(arguments, 1); + return function(event) { + var a = update([event || window.event], args); + return __method.apply(context, a); + } + } + + function curry() { + if (!arguments.length) return this; + var __method = this, args = slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } + + function delay(timeout) { + var __method = this, args = slice.call(arguments, 1); + timeout = timeout * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + } + + function defer() { + var args = update([0.01], arguments); + return this.delay.apply(this, args); + } + + function wrap(wrapper) { + var __method = this; + return function() { + var a = update([__method.bind(this)], arguments); + return wrapper.apply(this, a); + } + } + + function methodize() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + var a = update([this], arguments); + return __method.apply(null, a); + }; + } + + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})()); + + + +(function(proto) { + + + function toISOString() { + return this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z'; + } + + + function toJSON() { + return this.toISOString(); + } + + if (!proto.toISOString) proto.toISOString = toISOString; + if (!proto.toJSON) proto.toJSON = toJSON; + +})(Date.prototype); + + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + this.currentlyExecuting = false; + } catch(e) { + this.currentlyExecuting = false; + throw e; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, (function() { + var NATIVE_JSON_PARSE_SUPPORT = window.JSON && + typeof JSON.parse === 'function' && + JSON.parse('{"test": true}').test; + + function prepareReplacement(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; + } + + function gsub(pattern, replacement) { + var result = '', source = this, match; + replacement = prepareReplacement(replacement); + + if (Object.isString(pattern)) + pattern = RegExp.escape(pattern); + + if (!(pattern.length || pattern.source)) { + replacement = replacement(''); + return replacement + source.split('').join(replacement) + replacement; + } + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + } + + function sub(pattern, replacement, count) { + replacement = prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + } + + function scan(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + } + + function truncate(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + } + + function strip() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + function stripTags() { + return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); + } + + function stripScripts() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + } + + function extractScripts() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), + matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + } + + function evalScripts() { + return this.extractScripts().map(function(script) { return eval(script) }); + } + + function escapeHTML() { + return this.replace(/&/g,'&').replace(//g,'>'); + } + + function unescapeHTML() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + } + + + function toQueryParams(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()), + value = pair.length > 1 ? pair.join('=') : pair[0]; + + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + } + + function toArray() { + return this.split(''); + } + + function succ() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + } + + function times(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + } + + function camelize() { + return this.replace(/-+(.)?/g, function(match, chr) { + return chr ? chr.toUpperCase() : ''; + }); + } + + function capitalize() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + } + + function underscore() { + return this.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/-/g, '_') + .toLowerCase(); + } + + function dasherize() { + return this.replace(/_/g, '-'); + } + + function inspect(useDoubleQuotes) { + var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { + if (character in String.specialChar) { + return String.specialChar[character]; + } + return '\\u00' + character.charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } + + function unfilterJSON(filter) { + return this.replace(filter || Prototype.JSONFilter, '$1'); + } + + function isJSON() { + var str = this; + if (str.blank()) return false; + str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); + str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); + str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); + return (/^[\],:{}\s]*$/).test(str); + } + + function evalJSON(sanitize) { + var json = this.unfilterJSON(), + cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + if (cx.test(json)) { + json = json.replace(cx, function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + } + + function parseJSON() { + var json = this.unfilterJSON(); + return JSON.parse(json); + } + + function include(pattern) { + return this.indexOf(pattern) > -1; + } + + function startsWith(pattern) { + return this.lastIndexOf(pattern, 0) === 0; + } + + function endsWith(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.indexOf(pattern, d) === d; + } + + function empty() { + return this == ''; + } + + function blank() { + return /^\s*$/.test(this); + } + + function interpolate(object, pattern) { + return new Template(this, pattern).evaluate(object); + } + + return { + gsub: gsub, + sub: sub, + scan: scan, + truncate: truncate, + strip: String.prototype.trim || strip, + stripTags: stripTags, + stripScripts: stripScripts, + extractScripts: extractScripts, + evalScripts: evalScripts, + escapeHTML: escapeHTML, + unescapeHTML: unescapeHTML, + toQueryParams: toQueryParams, + parseQuery: toQueryParams, + toArray: toArray, + succ: succ, + times: times, + camelize: camelize, + capitalize: capitalize, + underscore: underscore, + dasherize: dasherize, + inspect: inspect, + unfilterJSON: unfilterJSON, + isJSON: isJSON, + evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, + include: include, + startsWith: startsWith, + endsWith: endsWith, + empty: empty, + blank: blank, + interpolate: interpolate + }; +})()); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (object && Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return (match[1] + ''); + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3], + pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = (function() { + function each(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + } + + function eachSlice(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + } + + function all(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + } + + function any(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + } + + function collect(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function detect(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + } + + function findAll(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function grep(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(RegExp.escape(filter)); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function include(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + } + + function inGroupsOf(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + } + + function inject(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + } + + function invoke(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + } + + function max(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + } + + function min(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + } + + function partition(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + } + + function pluck(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + } + + function reject(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function sortBy(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + } + + function toArray() { + return this.map(); + } + + function zip() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + } + + function size() { + return this.toArray().length; + } + + function inspect() { + return '#'; + } + + + + + + + + + + return { + each: each, + eachSlice: eachSlice, + all: all, + every: all, + any: any, + some: any, + collect: collect, + map: collect, + detect: detect, + findAll: findAll, + select: findAll, + filter: findAll, + grep: grep, + include: include, + member: include, + inGroupsOf: inGroupsOf, + inject: inject, + invoke: invoke, + max: max, + min: min, + partition: partition, + pluck: pluck, + reject: reject, + sortBy: sortBy, + toArray: toArray, + entries: toArray, + zip: zip, + size: size, + inspect: inspect, + find: detect + }; +})(); + +function $A(iterable) { + if (!iterable) return []; + if ('toArray' in Object(iterable)) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +Array.from = $A; + + +(function() { + var arrayProto = Array.prototype, + slice = arrayProto.slice, + _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available + + function each(iterator, context) { + for (var i = 0, length = this.length >>> 0; i < length; i++) { + if (i in this) iterator.call(context, this[i], i, this); + } + } + if (!_each) _each = each; + + function clear() { + this.length = 0; + return this; + } + + function first() { + return this[0]; + } + + function last() { + return this[this.length - 1]; + } + + function compact() { + return this.select(function(value) { + return value != null; + }); + } + + function flatten() { + return this.inject([], function(array, value) { + if (Object.isArray(value)) + return array.concat(value.flatten()); + array.push(value); + return array; + }); + } + + function without() { + var values = slice.call(arguments, 0); + return this.select(function(value) { + return !values.include(value); + }); + } + + function reverse(inline) { + return (inline === false ? this.toArray() : this)._reverse(); + } + + function uniq(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + } + + function intersect(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + } + + + function clone() { + return slice.call(this, 0); + } + + function size() { + return this.length; + } + + function inspect() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } + + function indexOf(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; + } + + function lastIndexOf(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; + } + + function concat() { + var array = slice.call(this, 0), item; + for (var i = 0, length = arguments.length; i < length; i++) { + item = arguments[i]; + if (Object.isArray(item) && !('callee' in item)) { + for (var j = 0, arrayLength = item.length; j < arrayLength; j++) + array.push(item[j]); + } else { + array.push(item); + } + } + return array; + } + + Object.extend(arrayProto, Enumerable); + + if (!arrayProto._reverse) + arrayProto._reverse = arrayProto.reverse; + + Object.extend(arrayProto, { + _each: _each, + clear: clear, + first: first, + last: last, + compact: compact, + flatten: flatten, + without: without, + reverse: reverse, + uniq: uniq, + intersect: intersect, + clone: clone, + toArray: clone, + size: size, + inspect: inspect + }); + + var CONCAT_ARGUMENTS_BUGGY = (function() { + return [].concat(arguments)[0][0] !== 1; + })(1,2) + + if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; + + if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; + if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})(); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + function initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + } + + + function _each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + + function set(key, value) { + return this._object[key] = value; + } + + function get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + } + + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + } + + function toObject() { + return Object.clone(this._object); + } + + + + function keys() { + return this.pluck('key'); + } + + function values() { + return this.pluck('value'); + } + + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + } + + function merge(object) { + return this.clone().update(object); + } + + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + function toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) { + var queryValues = []; + for (var i = 0, len = values.length, value; i < len; i++) { + value = values[i]; + queryValues.push(toQueryPair(key, value)); + } + return results.concat(queryValues); + } + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + } + + function inspect() { + return '#'; + } + + function clone() { + return new Hash(this); + } + + return { + initialize: initialize, + _each: _each, + set: set, + get: get, + unset: unset, + toObject: toObject, + toTemplateReplacements: toObject, + keys: keys, + values: values, + index: index, + merge: merge, + update: update, + toQueryString: toQueryString, + inspect: inspect, + toJSON: toObject, + clone: clone + }; +})()); + +Hash.from = $H; +Object.extend(Number.prototype, (function() { + function toColorPart() { + return this.toPaddedString(2, 16); + } + + function succ() { + return this + 1; + } + + function times(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + } + + function toPaddedString(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + } + + function abs() { + return Math.abs(this); + } + + function round() { + return Math.round(this); + } + + function ceil() { + return Math.ceil(this); + } + + function floor() { + return Math.floor(this); + } + + return { + toColorPart: toColorPart, + succ: succ, + times: times, + toPaddedString: toPaddedString, + abs: abs, + round: round, + ceil: ceil, + floor: floor + }; +})()); + +function $R(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { + function initialize(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + } + + function _each(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + } + + function include(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } + + return { + initialize: initialize, + _each: _each, + include: include + }; +})()); + + + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.isString(this.options.parameters) ? + this.options.parameters : + Object.toQueryString(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + params += (params ? '&' : '') + "_method=" + this.method; + this.method = 'post'; + } + + if (params && this.method === 'get') { + this.url += (this.url.include('?') ? '&' : '?') + params; + } + + this.parameters = params.toQueryParams(); + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300) || status == 304; + }, + + getStatus: function() { + try { + if (this.transport.status === 1223) return 204; + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null; } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + + + + + + + + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if (readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); + + +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + + + +(function(global) { + function shouldUseCache(tagName, attributes) { + if (tagName === 'select') return false; + if ('type' in attributes) return false; + return true; + } + + var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ + try { + var el = document.createElement(''); + return el.tagName.toLowerCase() === 'input' && el.name === 'x'; + } + catch(err) { + return false; + } + })(); + + var element = global.Element; + + global.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + + if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + + var node = shouldUseCache(tagName, attributes) ? + cache[tagName].cloneNode(false) : document.createElement(tagName); + + return Element.writeAttribute(node, attributes); + }; + + Object.extend(global.Element, element || { }); + if (element) global.Element.prototype = element.prototype; + +})(this); + +Element.idCounter = 1; +Element.cache = { }; + +Element._purgeElement = function(element) { + var uid = element._prototypeUID; + if (uid) { + Element.stopObserving(element); + element._prototypeUID = void 0; + delete Element.Storage[uid]; + } +} + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: (function(){ + + var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ + var el = document.createElement("select"), + isBuggy = true; + el.innerHTML = ""; + if (el.options && el.options[0]) { + isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; + } + el = null; + return isBuggy; + })(); + + var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ + try { + var el = document.createElement("table"); + if (el && el.tBodies) { + el.innerHTML = "test"; + var isBuggy = typeof el.tBodies[0] == "undefined"; + el = null; + return isBuggy; + } + } catch (e) { + return true; + } + })(); + + var LINK_ELEMENT_INNERHTML_BUGGY = (function() { + try { + var el = document.createElement('div'); + el.innerHTML = ""; + var isBuggy = (el.childNodes.length === 0); + el = null; + return isBuggy; + } catch(e) { + return true; + } + })(); + + var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY || + TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY; + + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { + var s = document.createElement("script"), + isBuggy = false; + try { + s.appendChild(document.createTextNode("")); + isBuggy = !s.firstChild || + s.firstChild && s.firstChild.nodeType !== 3; + } catch (e) { + isBuggy = true; + } + s = null; + return isBuggy; + })(); + + + function update(element, content) { + element = $(element); + var purgeElement = Element._purgeElement; + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + while (i--) purgeElement(descendants[i]); + + if (content && content.toElement) + content = content.toElement(); + + if (Object.isElement(content)) + return element.update().insert(content); + + content = Object.toHTML(content); + + var tagName = element.tagName.toUpperCase(); + + if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { + element.text = content; + return element; + } + + if (ANY_INNERHTML_BUGGY) { + if (tagName in Element._insertionTranslations.tags) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { + element.appendChild(node) + }); + } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf(' -1) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true); + nodes.each(function(node) { element.appendChild(node) }); + } + else { + element.innerHTML = content.stripScripts(); + } + } + else { + element.innerHTML = content.stripScripts(); + } + + content.evalScripts.bind(content).defer(); + return element; + } + + return update; + })(), + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), + attribute = pair.last(), + value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property, maximumLength) { + element = $(element); + maximumLength = maximumLength || -1; + var elements = []; + + while (element = element[property]) { + if (element.nodeType == 1) + elements.push(Element.extend(element)); + if (elements.length == maximumLength) + break; + } + + return elements; + }, + + ancestors: function(element) { + return Element.recursivelyCollect(element, 'parentNode'); + }, + + descendants: function(element) { + return Element.select(element, "*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + var results = [], child = $(element).firstChild; + while (child) { + if (child.nodeType === 1) { + results.push(Element.extend(child)); + } + child = child.nextSibling; + } + return results; + }, + + previousSiblings: function(element, maximumLength) { + return Element.recursivelyCollect(element, 'previousSibling'); + }, + + nextSiblings: function(element) { + return Element.recursivelyCollect(element, 'nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return Element.previousSiblings(element).reverse() + .concat(Element.nextSiblings(element)); + }, + + match: function(element, selector) { + element = $(element); + if (Object.isString(selector)) + return Prototype.Selector.match(element, selector); + return selector.match(element); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = Element.ancestors(element); + return Object.isNumber(expression) ? ancestors[expression] : + Prototype.Selector.find(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return Element.firstDescendant(element); + return Object.isNumber(expression) ? Element.descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.previousSiblings(), expression, index); + } else { + return element.recursivelyCollect("previousSibling", index + 1)[index]; + } + }, + + next: function(element, expression, index) { + element = $(element); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.nextSiblings(), expression, index); + } else { + var maximumLength = Object.isNumber(index) ? index + 1 : 1; + return element.recursivelyCollect("nextSibling", index + 1)[index]; + } + }, + + + select: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element); + }, + + adjacent: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element.parentNode).without(element); + }, + + identify: function(element) { + element = $(element); + var id = Element.readAttribute(element, 'id'); + if (id) return id; + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + Element.writeAttribute(element, 'id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return Element.getDimensions(element).height; + }, + + getWidth: function(element) { + return Element.getDimensions(element).width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!Element.hasClassName(element, className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return Element[Element.hasClassName(element, className) ? + 'removeClassName' : 'addClassName'](element, className); + }, + + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Element.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + source = $(source); + var p = Element.viewportOffset(source), delta = [0, 0], parent = null; + + element = $(element); + + if (Element.getStyle(element, 'position') == 'absolute') { + parent = Element.getOffsetParent(element); + delta = Element.viewportOffset(parent); + } + + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'height': case 'width': + if (!Element.visible(element)) return null; + + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = (function(){ + + var classProp = 'className', + forProp = 'for', + el = document.createElement('div'); + + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': forProp, + 'htmlFor': forProp + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute); + }, + _getAttr2: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'), f; + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + + if (String(value).indexOf('{') > -1) { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }; + } + else if (value === '') { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + }; + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + } + })(); + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr2, + src: v._getAttr2, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if (element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; +} + +if ('outerHTML' in document.documentElement) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(), + fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html, force) { + var div = new Element('div'), + t = Element._insertionTranslations.tags[tagName]; + + var workaround = false; + if (t) workaround = true; + else if (force) { + workaround = true; + t = ['', '', 0]; + } + + if (workaround) { + div.innerHTML = ' ' + t[0] + html + t[1]; + div.removeChild(div.firstChild); + for (var i = t[2]; i--; ) { + div = div.firstChild; + } + } + else { + div.innerHTML = html; + } + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
', 1], + TBODY: ['', '
', 2], + TR: ['', '
', 3], + TD: ['
', '
', 4], + SELECT: ['', 1] + } +}; + +(function() { + var tags = Element._insertionTranslations.tags; + Object.extend(tags, { + THEAD: tags.TBODY, + TFOOT: tags.TBODY, + TH: tags.TD + }); +})(); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')); + +Element.extend = (function() { + + function checkDeficiency(tagName) { + if (typeof window.Element != 'undefined') { + var proto = window.Element.prototype; + if (proto) { + var id = '_' + (Math.random()+'').slice(2), + el = document.createElement(tagName); + proto[id] = 'x'; + var isBuggy = (el[id] !== 'x'); + delete proto[id]; + el = null; + return isBuggy; + } + } + return false; + } + + function extendElementWith(element, methods) { + for (var property in methods) { + var value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + } + + var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + + if (Prototype.BrowserFeatures.SpecificElementExtensions) { + if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { + return function(element) { + if (element && typeof element._extendedByPrototype == 'undefined') { + var t = element.tagName; + if (t && (/^(?:object|applet|embed)$/i.test(t))) { + extendElementWith(element, Element.Methods); + extendElementWith(element, Element.Methods.Simulated); + extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); + } + } + return element; + } + } + return Prototype.K; + } + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || typeof element._extendedByPrototype != 'undefined' || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(); + + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + extendElementWith(element, methods); + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +if (document.documentElement.hasAttribute) { + Element.hasAttribute = function(element, attribute) { + return element.hasAttribute(attribute); + }; +} +else { + Element.hasAttribute = Element.Methods.Simulated.hasAttribute; +} + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods), + "BUTTON": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + var element = document.createElement(tagName), + proto = element['__proto__'] || element.constructor.prototype; + + element = null; + return proto; + } + + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + + if (F.ElementExtensions) { + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + + +document.viewport = { + + getDimensions: function() { + return { width: this.getWidth(), height: this.getHeight() }; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; + +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; + + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; + } else { + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = Element.Storage.UID++; + uid = element._prototypeUID; + } + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); + } + + return element; + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + }, + + clone: function(element, deep) { + if (!(element = $(element))) return; + var clone = element.cloneNode(deep); + clone._prototypeUID = void 0; + if (deep) { + var descendants = Element.select(clone, '*'), + i = descendants.length; + while (i--) { + descendants[i]._prototypeUID = void 0; + } + } + return Element.extend(clone); + }, + + purge: function(element) { + if (!(element = $(element))) return; + var purgeElement = Element._purgeElement; + + purgeElement(element); + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + + while (i--) purgeElement(descendants[i]); + + return null; + } +}); + +(function() { + + function toDecimal(pctString) { + var match = pctString.match(/^(\d+)%?$/i); + if (!match) return null; + return (Number(match[1]) / 100); + } + + function getPixelValue(value, property, context) { + var element = null; + if (Object.isElement(value)) { + element = value; + value = element.getStyle(property); + } + + if (value === null) { + return null; + } + + if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { + return window.parseFloat(value); + } + + var isPercentage = value.include('%'), isViewport = (context === document.viewport); + + if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) { + var style = element.style.left, rStyle = element.runtimeStyle.left; + element.runtimeStyle.left = element.currentStyle.left; + element.style.left = value || 0; + value = element.style.pixelLeft; + element.style.left = style; + element.runtimeStyle.left = rStyle; + + return value; + } + + if (element && isPercentage) { + context = context || element.parentNode; + var decimal = toDecimal(value); + var whole = null; + var position = element.getStyle('position'); + + var isHorizontal = property.include('left') || property.include('right') || + property.include('width'); + + var isVertical = property.include('top') || property.include('bottom') || + property.include('height'); + + if (context === document.viewport) { + if (isHorizontal) { + whole = document.viewport.getWidth(); + } else if (isVertical) { + whole = document.viewport.getHeight(); + } + } else { + if (isHorizontal) { + whole = $(context).measure('width'); + } else if (isVertical) { + whole = $(context).measure('height'); + } + } + + return (whole === null) ? 0 : whole * decimal; + } + + return 0; + } + + function toCSSPixels(number) { + if (Object.isString(number) && number.endsWith('px')) { + return number; + } + return number + 'px'; + } + + function isDisplayed(element) { + var originalElement = element; + while (element && element.parentNode) { + var display = element.getStyle('display'); + if (display === 'none') { + return false; + } + element = $(element.parentNode); + } + return true; + } + + var hasLayout = Prototype.K; + if ('currentStyle' in document.documentElement) { + hasLayout = function(element) { + if (!element.currentStyle.hasLayout) { + element.style.zoom = 1; + } + return element; + }; + } + + function cssNameFor(key) { + if (key.include('border')) key = key + '-width'; + return key.camelize(); + } + + Element.Layout = Class.create(Hash, { + initialize: function($super, element, preCompute) { + $super(); + this.element = $(element); + + Element.Layout.PROPERTIES.each( function(property) { + this._set(property, null); + }, this); + + if (preCompute) { + this._preComputing = true; + this._begin(); + Element.Layout.PROPERTIES.each( this._compute, this ); + this._end(); + this._preComputing = false; + } + }, + + _set: function(property, value) { + return Hash.prototype.set.call(this, property, value); + }, + + set: function(property, value) { + throw "Properties of Element.Layout are read-only."; + }, + + get: function($super, property) { + var value = $super(property); + return value === null ? this._compute(property) : value; + }, + + _begin: function() { + if (this._prepared) return; + + var element = this.element; + if (isDisplayed(element)) { + this._prepared = true; + return; + } + + var originalStyles = { + position: element.style.position || '', + width: element.style.width || '', + visibility: element.style.visibility || '', + display: element.style.display || '' + }; + + element.store('prototype_original_styles', originalStyles); + + var position = element.getStyle('position'), + width = element.getStyle('width'); + + if (width === "0px" || width === null) { + element.style.display = 'block'; + width = element.getStyle('width'); + } + + var context = (position === 'fixed') ? document.viewport : + element.parentNode; + + element.setStyle({ + position: 'absolute', + visibility: 'hidden', + display: 'block' + }); + + var positionedWidth = element.getStyle('width'); + + var newWidth; + if (width && (positionedWidth === width)) { + newWidth = getPixelValue(element, 'width', context); + } else if (position === 'absolute' || position === 'fixed') { + newWidth = getPixelValue(element, 'width', context); + } else { + var parent = element.parentNode, pLayout = $(parent).getLayout(); + + newWidth = pLayout.get('width') - + this.get('margin-left') - + this.get('border-left') - + this.get('padding-left') - + this.get('padding-right') - + this.get('border-right') - + this.get('margin-right'); + } + + element.setStyle({ width: newWidth + 'px' }); + + this._prepared = true; + }, + + _end: function() { + var element = this.element; + var originalStyles = element.retrieve('prototype_original_styles'); + element.store('prototype_original_styles', null); + element.setStyle(originalStyles); + this._prepared = false; + }, + + _compute: function(property) { + var COMPUTATIONS = Element.Layout.COMPUTATIONS; + if (!(property in COMPUTATIONS)) { + throw "Property not found."; + } + + return this._set(property, COMPUTATIONS[property].call(this, this.element)); + }, + + toObject: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var obj = {}; + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + var value = this.get(key); + if (value != null) obj[key] = value; + }, this); + return obj; + }, + + toHash: function() { + var obj = this.toObject.apply(this, arguments); + return new Hash(obj); + }, + + toCSS: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var css = {}; + + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; + + var value = this.get(key); + if (value != null) css[cssNameFor(key)] = value + 'px'; + }, this); + return css; + }, + + inspect: function() { + return "#"; + } + }); + + Object.extend(Element.Layout, { + PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), + + COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), + + COMPUTATIONS: { + 'height': function(element) { + if (!this._preComputing) this._begin(); + + var bHeight = this.get('border-box-height'); + if (bHeight <= 0) { + if (!this._preComputing) this._end(); + return 0; + } + + var bTop = this.get('border-top'), + bBottom = this.get('border-bottom'); + + var pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + if (!this._preComputing) this._end(); + + return bHeight - bTop - bBottom - pTop - pBottom; + }, + + 'width': function(element) { + if (!this._preComputing) this._begin(); + + var bWidth = this.get('border-box-width'); + if (bWidth <= 0) { + if (!this._preComputing) this._end(); + return 0; + } + + var bLeft = this.get('border-left'), + bRight = this.get('border-right'); + + var pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + if (!this._preComputing) this._end(); + + return bWidth - bLeft - bRight - pLeft - pRight; + }, + + 'padding-box-height': function(element) { + var height = this.get('height'), + pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + return height + pTop + pBottom; + }, + + 'padding-box-width': function(element) { + var width = this.get('width'), + pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + return width + pLeft + pRight; + }, + + 'border-box-height': function(element) { + if (!this._preComputing) this._begin(); + var height = element.offsetHeight; + if (!this._preComputing) this._end(); + return height; + }, + + 'border-box-width': function(element) { + if (!this._preComputing) this._begin(); + var width = element.offsetWidth; + if (!this._preComputing) this._end(); + return width; + }, + + 'margin-box-height': function(element) { + var bHeight = this.get('border-box-height'), + mTop = this.get('margin-top'), + mBottom = this.get('margin-bottom'); + + if (bHeight <= 0) return 0; + + return bHeight + mTop + mBottom; + }, + + 'margin-box-width': function(element) { + var bWidth = this.get('border-box-width'), + mLeft = this.get('margin-left'), + mRight = this.get('margin-right'); + + if (bWidth <= 0) return 0; + + return bWidth + mLeft + mRight; + }, + + 'top': function(element) { + var offset = element.positionedOffset(); + return offset.top; + }, + + 'bottom': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pHeight = parent.measure('height'); + + var mHeight = this.get('border-box-height'); + + return pHeight - mHeight - offset.top; + }, + + 'left': function(element) { + var offset = element.positionedOffset(); + return offset.left; + }, + + 'right': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pWidth = parent.measure('width'); + + var mWidth = this.get('border-box-width'); + + return pWidth - mWidth - offset.left; + }, + + 'padding-top': function(element) { + return getPixelValue(element, 'paddingTop'); + }, + + 'padding-bottom': function(element) { + return getPixelValue(element, 'paddingBottom'); + }, + + 'padding-left': function(element) { + return getPixelValue(element, 'paddingLeft'); + }, + + 'padding-right': function(element) { + return getPixelValue(element, 'paddingRight'); + }, + + 'border-top': function(element) { + return getPixelValue(element, 'borderTopWidth'); + }, + + 'border-bottom': function(element) { + return getPixelValue(element, 'borderBottomWidth'); + }, + + 'border-left': function(element) { + return getPixelValue(element, 'borderLeftWidth'); + }, + + 'border-right': function(element) { + return getPixelValue(element, 'borderRightWidth'); + }, + + 'margin-top': function(element) { + return getPixelValue(element, 'marginTop'); + }, + + 'margin-bottom': function(element) { + return getPixelValue(element, 'marginBottom'); + }, + + 'margin-left': function(element) { + return getPixelValue(element, 'marginLeft'); + }, + + 'margin-right': function(element) { + return getPixelValue(element, 'marginRight'); + } + } + }); + + if ('getBoundingClientRect' in document.documentElement) { + Object.extend(Element.Layout.COMPUTATIONS, { + 'right': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.right - rect.right).round(); + }, + + 'bottom': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.bottom - rect.bottom).round(); + } + }); + } + + Element.Offset = Class.create({ + initialize: function(left, top) { + this.left = left.round(); + this.top = top.round(); + + this[0] = this.left; + this[1] = this.top; + }, + + relativeTo: function(offset) { + return new Element.Offset( + this.left - offset.left, + this.top - offset.top + ); + }, + + inspect: function() { + return "#".interpolate(this); + }, + + toString: function() { + return "[#{left}, #{top}]".interpolate(this); + }, + + toArray: function() { + return [this.left, this.top]; + } + }); + + function getLayout(element, preCompute) { + return new Element.Layout(element, preCompute); + } + + function measure(element, property) { + return $(element).getLayout().get(property); + } + + function getDimensions(element) { + element = $(element); + var display = Element.getStyle(element, 'display'); + + if (display && display !== 'none') { + return { width: element.offsetWidth, height: element.offsetHeight }; + } + + var style = element.style; + var originalStyles = { + visibility: style.visibility, + position: style.position, + display: style.display + }; + + var newStyles = { + visibility: 'hidden', + display: 'block' + }; + + if (originalStyles.position !== 'fixed') + newStyles.position = 'absolute'; + + Element.setStyle(element, newStyles); + + var dimensions = { + width: element.offsetWidth, + height: element.offsetHeight + }; + + Element.setStyle(element, originalStyles); + + return dimensions; + } + + function getOffsetParent(element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var isInline = (Element.getStyle(element, 'display') === 'inline'); + if (!isInline && element.offsetParent) return $(element.offsetParent); + + while ((element = element.parentNode) && element !== document.body) { + if (Element.getStyle(element, 'position') !== 'static') { + return isHtml(element) ? $(document.body) : $(element); + } + } + + return $(document.body); + } + + + function cumulativeOffset(element) { + element = $(element); + var valueT = 0, valueL = 0; + if (element.parentNode) { + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + } + return new Element.Offset(valueL, valueT); + } + + function positionedOffset(element) { + element = $(element); + + var layout = element.getLayout(); + + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (isBody(element)) break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + + valueL -= layout.get('margin-top'); + valueT -= layout.get('margin-left'); + + return new Element.Offset(valueL, valueT); + } + + function cumulativeScrollOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return new Element.Offset(valueL, valueT); + } + + function viewportOffset(forElement) { + element = $(element); + var valueT = 0, valueL = 0, docBody = document.body; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == docBody && + Element.getStyle(element, 'position') == 'absolute') break; + } while (element = element.offsetParent); + + element = forElement; + do { + if (element != docBody) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + return new Element.Offset(valueL, valueT); + } + + function absolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } + + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), + pOffset = offsetParent.viewportOffset(); + + var offset = eOffset.relativeTo(pOffset); + var layout = element.getLayout(); + + element.store('prototype_absolutize_original_styles', { + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') + }); + + element.setStyle({ + position: 'absolute', + top: offset.top + 'px', + left: offset.left + 'px', + width: layout.get('width') + 'px', + height: layout.get('height') + 'px' + }); + + return element; + } + + function relativize(element) { + element = $(element); + if (Element.getStyle(element, 'position') === 'relative') { + return element; + } + + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + + if (Prototype.Browser.IE) { + getOffsetParent = getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + positionedOffset = positionedOffset.wrap(function(proceed, element) { + element = $(element); + if (!element.parentNode) return new Element.Offset(0, 0); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + hasLayout(offsetParent); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + }); + } else if (Prototype.Browser.Webkit) { + cumulativeOffset = function(element) { + element = $(element); + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return new Element.Offset(valueL, valueT); + }; + } + + + Element.addMethods({ + getLayout: getLayout, + measure: measure, + getDimensions: getDimensions, + getOffsetParent: getOffsetParent, + cumulativeOffset: cumulativeOffset, + positionedOffset: positionedOffset, + cumulativeScrollOffset: cumulativeScrollOffset, + viewportOffset: viewportOffset, + absolutize: absolutize, + relativize: relativize + }); + + function isBody(element) { + return element.nodeName.toUpperCase() === 'BODY'; + } + + function isHtml(element) { + return element.nodeName.toUpperCase() === 'HTML'; + } + + function isDocument(element) { + return element.nodeType === Node.DOCUMENT_NODE; + } + + function isDetached(element) { + return element !== document.body && + !Element.descendantOf(element, document.body); + } + + if ('getBoundingClientRect' in document.documentElement) { + Element.addMethods({ + viewportOffset: function(element) { + element = $(element); + if (isDetached(element)) return new Element.Offset(0, 0); + + var rect = element.getBoundingClientRect(), + docEl = document.documentElement; + return new Element.Offset(rect.left - docEl.clientLeft, + rect.top - docEl.clientTop); + } + }); + } +})(); +window.$$ = function() { + var expression = $A(arguments).join(', '); + return Prototype.Selector.select(expression, document); +}; + +Prototype.Selector = (function() { + + function select() { + throw new Error('Method "Prototype.Selector.select" must be defined.'); + } + + function match() { + throw new Error('Method "Prototype.Selector.match" must be defined.'); + } + + function find(elements, expression, index) { + index = index || 0; + var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; + + for (i = 0; i < length; i++) { + if (match(elements[i], expression) && index == matchIndex++) { + return Element.extend(elements[i]); + } + } + } + + function extendElements(elements) { + for (var i = 0, length = elements.length; i < length; i++) { + Element.extend(elements[i]); + } + return elements; + } + + + var K = Prototype.K; + + return { + select: select, + match: match, + find: find, + extendElements: (Element.extend === K) ? K : extendElements, + extendElement: Element.extend + }; +})(); +Prototype._original_property = window.Sizzle; +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +(function(){ + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
"; + + if ( div.getElementsByClassName("e").length === 0 ) + return; + + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + + +window.Sizzle = Sizzle; + +})(); + +;(function(engine) { + var extendElements = Prototype.Selector.extendElements; + + function select(selector, scope) { + return extendElements(engine(selector, scope || document)); + } + + function match(element, selector) { + return engine.matches(selector, [element]).length == 1; + } + + Prototype.Selector.engine = engine; + Prototype.Selector.select = select; + Prototype.Selector.match = match; +})(Sizzle); + +window.Sizzle = Prototype._original_property; +delete Prototype._original_property; + +var Form = { + reset: function(form) { + form = $(form); + form.reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit, accumulator, initial; + + if (options.hash) { + initial = {}; + accumulator = function(result, key, value) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } else result[key] = value; + return result; + }; + } else { + initial = ''; + accumulator = function(result, key, value) { + return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value); + } + } + + return elements.inject(initial, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + result = accumulator(result, key, value); + } + } + return result; + }); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + var elements = $(form).getElementsByTagName('*'), + element, + arr = [ ], + serializers = Form.Element.Serializers; + for (var i = 0; element = elements[i]; i++) { + arr.push(element); + } + return arr.inject([], function(elements, child) { + if (serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + }) + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return /^(?:input|select|textarea)$/i.test(element.tagName); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + var element = form.findFirstElement(); + if (element) element.activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !(/^(?:button|reset|submit)$/i.test(element.type)))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; + +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = (function() { + function input(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return inputSelector(element, value); + default: + return valueSelector(element, value); + } + } + + function inputSelector(element, value) { + if (Object.isUndefined(value)) + return element.checked ? element.value : null; + else element.checked = !!value; + } + + function valueSelector(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + } + + function select(element, value) { + if (Object.isUndefined(value)) + return (element.type === 'select-one' ? selectOne : selectMany)(element); + + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + + function selectOne(element) { + var index = element.selectedIndex; + return index >= 0 ? optionValue(element.options[index]) : null; + } + + function selectMany(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(optionValue(opt)); + } + return values; + } + + function optionValue(opt) { + return Element.hasAttribute(opt, 'value') ? opt.value : opt.text; + } + + return { + input: input, + inputSelector: inputSelector, + textarea: valueSelector, + select: select, + selectOne: selectOne, + selectMany: selectMany, + optionValue: optionValue, + button: valueSelector + }; +})(); + +/*--------------------------------------------------------------------------*/ + + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +(function() { + + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: {} + }; + + var docEl = document.documentElement; + var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl + && 'onmouseleave' in docEl; + + + + var isIELegacyEvent = function(event) { return false; }; + + if (window.attachEvent) { + if (window.addEventListener) { + isIELegacyEvent = function(event) { + return !(event instanceof window.Event); + }; + } else { + isIELegacyEvent = function(event) { return true; }; + } + } + + var _isButton; + + function _isButtonForDOMEvents(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + } + + var legacyButtonMap = { 0: 1, 1: 4, 2: 2 }; + function _isButtonForLegacyEvents(event, code) { + return event.button === legacyButtonMap[code]; + } + + function _isButtonForWebKit(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 2 || (event.which == 1 && event.metaKey); + case 2: return event.which == 3; + default: return false; + } + } + + if (window.attachEvent) { + if (!window.addEventListener) { + _isButton = _isButtonForLegacyEvents; + } else { + _isButton = function(event, code) { + return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) : + _isButtonForDOMEvents(event, code); + } + } + } else if (Prototype.Browser.WebKit) { + _isButton = _isButtonForWebKit; + } else { + _isButton = _isButtonForDOMEvents; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + + if (!expression) return element; + while (element) { + if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { + return Element.extend(element); + } + element = element.parentNode; + } + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop + }; + + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (window.attachEvent) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': + case 'mouseenter': + element = event.fromElement; + break; + case 'mouseout': + case 'mouseleave': + element = event.toElement; + break; + default: + return null; + } + return Element.extend(element); + } + + var additionalMethods = { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return '[object Event]' } + }; + + Event.extend = function(event, element) { + if (!event) return false; + + if (!isIELegacyEvent(event)) return event; + + if (event._extendedByPrototype) return event; + event._extendedByPrototype = Prototype.emptyFunction; + + var pointer = Event.pointer(event); + + Object.extend(event, { + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + + Object.extend(event, methods); + Object.extend(event, additionalMethods); + + return event; + }; + } else { + Event.extend = Prototype.K; + } + + if (window.addEventListener) { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; + Object.extend(Event.prototype, methods); + } + + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } + + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined(respondersForEvent)) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } + + if (respondersForEvent.pluck('handler').include(handler)) return false; + + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) + return false; + + if (event.eventName !== eventName) + return false; + + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); + + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } + + if (parent === element) return; + + handler.call(element, event); + }; + } + } else { + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; + } + } + + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } + + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } + + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K, + translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { + _getDOMEventName = function(eventName) { + return (translations[eventName] || eventName); + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onlosecapture", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + if (!registry) return element; + + if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key; + stopObserving(element, eventName); + }); + return element; + } + + var responders = registry.get(eventName); + if (!responders) return element; + + if (!handler) { + responders.each(function(r) { + stopObserving(element, eventName, r.handler); + }); + return element; + } + + var i = responders.length, responder; + while (i--) { + if (responders[i].handler === handler) { + responder = responders[i]; + break; + } + } + if (!responder) return element; + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onlosecapture", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', bubble, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onlosecapture'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + Event.Handler = Class.create({ + initialize: function(element, eventName, selector, callback) { + this.element = $(element); + this.eventName = eventName; + this.selector = selector; + this.callback = callback; + this.handler = this.handleEvent.bind(this); + }, + + start: function() { + Event.observe(this.element, this.eventName, this.handler); + return this; + }, + + stop: function() { + Event.stopObserving(this.element, this.eventName, this.handler); + return this; + }, + + handleEvent: function(event) { + var element = Event.findElement(event, this.selector); + if (element) this.callback.call(this.element, event, element); + } + }); + + function on(element, eventName, selector, callback) { + element = $(element); + if (Object.isFunction(selector) && Object.isUndefined(callback)) { + callback = selector, selector = null; + } + + return new Event.Handler(element, eventName, selector, callback).start(); + } + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving, + on: on + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving, + + on: on + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + on: on.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearTimeout(timer); + document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); + } else { + document.observe('readystatechange', checkReadyState); + if (window == top) + timer = pollDoScroll.defer(); + } + + Event.observe(window, 'load', fireContentLoadedEvent); +})(); + +Element.addMethods(); + +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +var Position = { + includeScrollOffsets: false, + + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ + +(function() { + window.Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + }, + + findElements: function(rootElement) { + return Prototype.Selector.select(this.expression, rootElement); + }, + + match: function(element) { + return Prototype.Selector.match(element, this.expression); + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#"; + } + }); + + Object.extend(Selector, { + matchElements: function(elements, expression) { + var match = Prototype.Selector.match, + results = []; + + for (var i = 0, length = elements.length; i < length; i++) { + var element = elements[i]; + if (match(element, expression)) { + results.push(Element.extend(element)); + } + } + return results; + }, + + findElement: function(elements, expression, index) { + index = index || 0; + var matchIndex = 0, element; + for (var i = 0, length = elements.length; i < length; i++) { + element = elements[i]; + if (Prototype.Selector.match(element, expression) && index === matchIndex++) { + return Element.extend(element); + } + } + }, + + findChildElements: function(element, expressions) { + var selector = expressions.toArray().join(', '); + return Prototype.Selector.select(selector, element || document); + } + }); +})(); diff --git a/js/src/builder.js b/js/src/builder.js new file mode 100644 index 0000000..dba8bec --- /dev/null +++ b/js/src/builder.js @@ -0,0 +1,136 @@ +// script.aculo.us builder.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008 + +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +var Builder = { + NODEMAP: { + AREA: 'map', + CAPTION: 'table', + COL: 'table', + COLGROUP: 'table', + LEGEND: 'fieldset', + OPTGROUP: 'select', + OPTION: 'select', + PARAM: 'object', + TBODY: 'table', + TD: 'table', + TFOOT: 'table', + TH: 'table', + THEAD: 'table', + TR: 'table' + }, + // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, + // due to a Firefox bug + node: function(elementName) { + elementName = elementName.toUpperCase(); + + // try innerHTML approach + var parentTag = this.NODEMAP[elementName] || 'div'; + var parentElement = document.createElement(parentTag); + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" + elementName + ">"; + } catch(e) {} + var element = parentElement.firstChild || null; + + // see if browser added wrapping tags + if(element && (element.tagName.toUpperCase() != elementName)) + element = element.getElementsByTagName(elementName)[0]; + + // fallback to createElement approach + if(!element) element = document.createElement(elementName); + + // abort if nothing could be created + if(!element) return; + + // attributes (or text) + if(arguments[1]) + if(this._isStringOrNumber(arguments[1]) || + (arguments[1] instanceof Array) || + arguments[1].tagName) { + this._children(element, arguments[1]); + } else { + var attrs = this._attributes(arguments[1]); + if(attrs.length) { + try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 + parentElement.innerHTML = "<" +elementName + " " + + attrs + ">"; + } catch(e) {} + element = parentElement.firstChild || null; + // workaround firefox 1.0.X bug + if(!element) { + element = document.createElement(elementName); + for(attr in arguments[1]) + element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; + } + if(element.tagName.toUpperCase() != elementName) + element = parentElement.getElementsByTagName(elementName)[0]; + } + } + + // text, or array of children + if(arguments[2]) + this._children(element, arguments[2]); + + return $(element); + }, + _text: function(text) { + return document.createTextNode(text); + }, + + ATTR_MAP: { + 'className': 'class', + 'htmlFor': 'for' + }, + + _attributes: function(attributes) { + var attrs = []; + for(attribute in attributes) + attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + + '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"'); + return attrs.join(" "); + }, + _children: function(element, children) { + if(children.tagName) { + element.appendChild(children); + return; + } + if(typeof children=='object') { // array can hold nodes and text + children.flatten().each( function(e) { + if(typeof e=='object') + element.appendChild(e); + else + if(Builder._isStringOrNumber(e)) + element.appendChild(Builder._text(e)); + }); + } else + if(Builder._isStringOrNumber(children)) + element.appendChild(Builder._text(children)); + }, + _isStringOrNumber: function(param) { + return(typeof param=='string' || typeof param=='number'); + }, + build: function(html) { + var element = this.node('div'); + $(element).update(html.strip()); + return element.down(); + }, + dump: function(scope) { + if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope + + var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + + "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + + "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ + "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ + "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ + "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); + + tags.each( function(tag){ + scope[tag] = function() { + return Builder.node.apply(Builder, [tag].concat($A(arguments))); + }; + }); + } +}; \ No newline at end of file diff --git a/js/src/controls.js b/js/src/controls.js new file mode 100644 index 0000000..c56ccb7 --- /dev/null +++ b/js/src/controls.js @@ -0,0 +1,965 @@ +// script.aculo.us controls.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008 + +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2008 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005-2008 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = { }; +Autocompleter.Base = Class.create({ + baseInitialize: function(element, update, options) { + element = $(element); + this.element = element; + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + this.oldElementValue = this.element.value; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || { }; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + // Force carriage returns as token delimiters anyway + if (!this.options.tokens.include('\n')) + this.options.tokens.push('\n'); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (Prototype.Browser.IE) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index--; + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++; + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = $(selectedElement).select('.' + this.options.select) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var bounds = this.getTokenBounds(); + if (bounds[0] != -1) { + var newValue = this.element.value.substr(0, bounds[0]); + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value + this.element.value.substr(bounds[1]); + } else { + this.element.value = value; + } + this.oldElementValue = this.element.value; + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + this.tokenBounds = null; + if(this.getToken().length>=this.options.minChars) { + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + this.oldElementValue = this.element.value; + }, + + getToken: function() { + var bounds = this.getTokenBounds(); + return this.element.value.substring(bounds[0], bounds[1]).strip(); + }, + + getTokenBounds: function() { + if (null != this.tokenBounds) return this.tokenBounds; + var value = this.element.value; + if (value.strip().empty()) return [-1, 0]; + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); + var offset = (diff == this.oldElementValue.length ? 1 : 0); + var prevTokenPos = -1, nextTokenPos = value.length; + var tp; + for (var index = 0, l = this.options.tokens.length; index < l; ++index) { + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); + if (tp > prevTokenPos) prevTokenPos = tp; + tp = value.indexOf(this.options.tokens[index], diff + offset); + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; + } + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); + } +}); + +Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { + var boundary = Math.min(newS.length, oldS.length); + for (var index = 0; index < boundary; ++index) + if (newS[index] != oldS[index]) + return index; + return boundary; +}; + +Ajax.Autocompleter = Class.create(Autocompleter.Base, { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + this.startIndicator(); + + var entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); + return "
      " + ret.join('') + "
    "; + } + }, options || { }); + } +}); + +// AJAX in-place editor and collection editor +// Full rewrite by Christophe Porteneuve (April 2007). + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +}; + +Ajax.InPlaceEditor = Class.create({ + initialize: function(element, url, options) { + this.url = url; + this.element = element = $(element); + this.prepareOptions(); + this._controls = { }; + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! + Object.extend(this.options, options || { }); + if (!this.options.formId && this.element.id) { + this.options.formId = this.element.id + '-inplaceeditor'; + if ($(this.options.formId)) + this.options.formId = ''; + } + if (this.options.externalControl) + this.options.externalControl = $(this.options.externalControl); + if (!this.options.externalControl) + this.options.externalControlOnly = false; + this._originalBackground = this.element.getStyle('background-color') || 'transparent'; + this.element.title = this.options.clickToEditText; + this._boundCancelHandler = this.handleFormCancellation.bind(this); + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); + this._boundFailureHandler = this.handleAJAXFailure.bind(this); + this._boundSubmitHandler = this.handleFormSubmission.bind(this); + this._boundWrapperHandler = this.wrapUp.bind(this); + this.registerListeners(); + }, + checkForEscapeOrReturn: function(e) { + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; + if (Event.KEY_ESC == e.keyCode) + this.handleFormCancellation(e); + else if (Event.KEY_RETURN == e.keyCode) + this.handleFormSubmission(e); + }, + createControl: function(mode, handler, extraClasses) { + var control = this.options[mode + 'Control']; + var text = this.options[mode + 'Text']; + if ('button' == control) { + var btn = document.createElement('input'); + btn.type = 'submit'; + btn.value = text; + btn.className = 'editor_' + mode + '_button'; + if ('cancel' == mode) + btn.onclick = this._boundCancelHandler; + this._form.appendChild(btn); + this._controls[mode] = btn; + } else if ('link' == control) { + var link = document.createElement('a'); + link.href = '#'; + link.appendChild(document.createTextNode(text)); + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; + link.className = 'editor_' + mode + '_link'; + if (extraClasses) + link.className += ' ' + extraClasses; + this._form.appendChild(link); + this._controls[mode] = link; + } + }, + createEditField: function() { + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); + var fld; + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { + fld = document.createElement('input'); + fld.type = 'text'; + var size = this.options.size || this.options.cols || 0; + if (0 < size) fld.size = size; + } else { + fld = document.createElement('textarea'); + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); + fld.cols = this.options.cols || 40; + } + fld.name = this.options.paramName; + fld.value = text; // No HTML breaks conversion anymore + fld.className = 'editor_field'; + if (this.options.submitOnBlur) + fld.onblur = this._boundSubmitHandler; + this._controls.editor = fld; + if (this.options.loadTextURL) + this.loadExternalText(); + this._form.appendChild(this._controls.editor); + }, + createForm: function() { + var ipe = this; + function addText(mode, condition) { + var text = ipe.options['text' + mode + 'Controls']; + if (!text || condition === false) return; + ipe._form.appendChild(document.createTextNode(text)); + }; + this._form = $(document.createElement('form')); + this._form.id = this.options.formId; + this._form.addClassName(this.options.formClassName); + this._form.onsubmit = this._boundSubmitHandler; + this.createEditField(); + if ('textarea' == this._controls.editor.tagName.toLowerCase()) + this._form.appendChild(document.createElement('br')); + if (this.options.onFormCustomization) + this.options.onFormCustomization(this, this._form); + addText('Before', this.options.okControl || this.options.cancelControl); + this.createControl('ok', this._boundSubmitHandler); + addText('Between', this.options.okControl && this.options.cancelControl); + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); + addText('After', this.options.okControl || this.options.cancelControl); + }, + destroy: function() { + if (this._oldInnerHTML) + this.element.innerHTML = this._oldInnerHTML; + this.leaveEditMode(); + this.unregisterListeners(); + }, + enterEditMode: function(e) { + if (this._saving || this._editing) return; + this._editing = true; + this.triggerCallback('onEnterEditMode'); + if (this.options.externalControl) + this.options.externalControl.hide(); + this.element.hide(); + this.createForm(); + this.element.parentNode.insertBefore(this._form, this.element); + if (!this.options.loadTextURL) + this.postProcessEditField(); + if (e) Event.stop(e); + }, + enterHover: function(e) { + if (this.options.hoverClassName) + this.element.addClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onEnterHover'); + }, + getText: function() { + return this.element.innerHTML.unescapeHTML(); + }, + handleAJAXFailure: function(transport) { + this.triggerCallback('onFailure', transport); + if (this._oldInnerHTML) { + this.element.innerHTML = this._oldInnerHTML; + this._oldInnerHTML = null; + } + }, + handleFormCancellation: function(e) { + this.wrapUp(); + if (e) Event.stop(e); + }, + handleFormSubmission: function(e) { + var form = this._form; + var value = $F(this._controls.editor); + this.prepareSubmission(); + var params = this.options.callback(form, value) || ''; + if (Object.isString(params)) + params = params.toQueryParams(); + params.editorId = this.element.id; + if (this.options.htmlResponse) { + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Updater({ success: this.element }, this.url, options); + } else { + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.url, options); + } + if (e) Event.stop(e); + }, + leaveEditMode: function() { + this.element.removeClassName(this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + if (this.options.externalControl) + this.options.externalControl.show(); + this._saving = false; + this._editing = false; + this._oldInnerHTML = null; + this.triggerCallback('onLeaveEditMode'); + }, + leaveHover: function(e) { + if (this.options.hoverClassName) + this.element.removeClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onLeaveHover'); + }, + loadExternalText: function() { + this._form.addClassName(this.options.loadingClassName); + this._controls.editor.disabled = true; + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._form.removeClassName(this.options.loadingClassName); + var text = transport.responseText; + if (this.options.stripLoadedTextTags) + text = text.stripTags(); + this._controls.editor.value = text; + this._controls.editor.disabled = false; + this.postProcessEditField(); + }.bind(this), + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + postProcessEditField: function() { + var fpc = this.options.fieldPostCreation; + if (fpc) + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); + }, + prepareOptions: function() { + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); + [this._extraDefaultOptions].flatten().compact().each(function(defs) { + Object.extend(this.options, defs); + }.bind(this)); + }, + prepareSubmission: function() { + this._saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + registerListeners: function() { + this._listeners = { }; + var listener; + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { + listener = this[pair.value].bind(this); + this._listeners[pair.key] = listener; + if (!this.options.externalControlOnly) + this.element.observe(pair.key, listener); + if (this.options.externalControl) + this.options.externalControl.observe(pair.key, listener); + }.bind(this)); + }, + removeForm: function() { + if (!this._form) return; + this._form.remove(); + this._form = null; + this._controls = { }; + }, + showSaving: function() { + this._oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + this.element.addClassName(this.options.savingClassName); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + }, + triggerCallback: function(cbName, arg) { + if ('function' == typeof this.options[cbName]) { + this.options[cbName](this, arg); + } + }, + unregisterListeners: function() { + $H(this._listeners).each(function(pair) { + if (!this.options.externalControlOnly) + this.element.stopObserving(pair.key, pair.value); + if (this.options.externalControl) + this.options.externalControl.stopObserving(pair.key, pair.value); + }.bind(this)); + }, + wrapUp: function(transport) { + this.leaveEditMode(); + // Can't use triggerCallback due to backward compatibility: requires + // binding + direct element + this._boundComplete(transport, this.element); + } +}); + +Object.extend(Ajax.InPlaceEditor.prototype, { + dispose: Ajax.InPlaceEditor.prototype.destroy +}); + +Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { + initialize: function($super, element, url, options) { + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; + $super(element, url, options); + }, + + createEditField: function() { + var list = document.createElement('select'); + list.name = this.options.paramName; + list.size = 1; + this._controls.editor = list; + this._collection = this.options.collection || []; + if (this.options.loadCollectionURL) + this.loadCollection(); + else + this.checkForExternalText(); + this._form.appendChild(this._controls.editor); + }, + + loadCollection: function() { + this._form.addClassName(this.options.loadingClassName); + this.showLoadingText(this.options.loadingCollectionText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + var js = transport.responseText.strip(); + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check + throw('Server returned an invalid collection representation.'); + this._collection = eval(js); + this.checkForExternalText(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadCollectionURL, options); + }, + + showLoadingText: function(text) { + this._controls.editor.disabled = true; + var tempOption = this._controls.editor.firstChild; + if (!tempOption) { + tempOption = document.createElement('option'); + tempOption.value = ''; + this._controls.editor.appendChild(tempOption); + tempOption.selected = true; + } + tempOption.update((text || '').stripScripts().stripTags()); + }, + + checkForExternalText: function() { + this._text = this.getText(); + if (this.options.loadTextURL) + this.loadExternalText(); + else + this.buildOptionList(); + }, + + loadExternalText: function() { + this.showLoadingText(this.options.loadingText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._text = transport.responseText.strip(); + this.buildOptionList(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + + buildOptionList: function() { + this._form.removeClassName(this.options.loadingClassName); + this._collection = this._collection.map(function(entry) { + return 2 === entry.length ? entry : [entry, entry].flatten(); + }); + var marker = ('value' in this.options) ? this.options.value : this._text; + var textFound = this._collection.any(function(entry) { + return entry[0] == marker; + }.bind(this)); + this._controls.editor.update(''); + var option; + this._collection.each(function(entry, index) { + option = document.createElement('option'); + option.value = entry[0]; + option.selected = textFound ? entry[0] == marker : 0 == index; + option.appendChild(document.createTextNode(entry[1])); + this._controls.editor.appendChild(option); + }.bind(this)); + this._controls.editor.disabled = false; + Field.scrollFreeActivate(this._controls.editor); + } +}); + +//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** +//**** This only exists for a while, in order to let **** +//**** users adapt to the new API. Read up on the new **** +//**** API and convert your code to it ASAP! **** + +Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { + if (!options) return; + function fallback(name, expr) { + if (name in options || expr === undefined) return; + options[name] = expr; + }; + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : + options.cancelLink == options.cancelButton == false ? false : undefined))); + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : + options.okLink == options.okButton == false ? false : undefined))); + fallback('highlightColor', options.highlightcolor); + fallback('highlightEndColor', options.highlightendcolor); +}; + +Object.extend(Ajax.InPlaceEditor, { + DefaultOptions: { + ajaxOptions: { }, + autoRows: 3, // Use when multi-line w/ rows == 1 + cancelControl: 'link', // 'link'|'button'|false + cancelText: 'cancel', + clickToEditText: 'Click to edit', + externalControl: null, // id|elt + externalControlOnly: false, + fieldPostCreation: 'activate', // 'activate'|'focus'|false + formClassName: 'inplaceeditor-form', + formId: null, // id|elt + highlightColor: '#ffff99', + highlightEndColor: '#ffffff', + hoverClassName: '', + htmlResponse: true, + loadingClassName: 'inplaceeditor-loading', + loadingText: 'Loading...', + okControl: 'button', // 'link'|'button'|false + okText: 'ok', + paramName: 'value', + rows: 1, // If 1 and multi-line, uses autoRows + savingClassName: 'inplaceeditor-saving', + savingText: 'Saving...', + size: 0, + stripLoadedTextTags: false, + submitOnBlur: false, + textAfterControls: '', + textBeforeControls: '', + textBetweenControls: '' + }, + DefaultCallbacks: { + callback: function(form) { + return Form.serialize(form); + }, + onComplete: function(transport, element) { + // For backward compatibility, this one is bound to the IPE, and passes + // the element directly. It was too often customized, so we don't break it. + new Effect.Highlight(element, { + startcolor: this.options.highlightColor, keepBackgroundImage: true }); + }, + onEnterEditMode: null, + onEnterHover: function(ipe) { + ipe.element.style.backgroundColor = ipe.options.highlightColor; + if (ipe._effect) + ipe._effect.cancel(); + }, + onFailure: function(transport, ipe) { + alert('Error communication with the server: ' + transport.responseText.stripTags()); + }, + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. + onLeaveEditMode: null, + onLeaveHover: function(ipe) { + ipe._effect = new Effect.Highlight(ipe.element, { + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, + restorecolor: ipe._originalBackground, keepBackgroundImage: true + }); + } + }, + Listeners: { + click: 'enterEditMode', + keydown: 'checkForEscapeOrReturn', + mouseover: 'enterHover', + mouseout: 'leaveHover' + } +}); + +Ajax.InPlaceCollectionEditor.DefaultOptions = { + loadingCollectionText: 'Loading options...' +}; + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create({ + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}); \ No newline at end of file diff --git a/js/src/dragdrop.js b/js/src/dragdrop.js new file mode 100644 index 0000000..07c98e2 --- /dev/null +++ b/js/src/dragdrop.js @@ -0,0 +1,975 @@ +// script.aculo.us dragdrop.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008 + +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2008 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(Object.isUndefined(Effect)) + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || { }); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if(Object.isArray(containment)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var drop, affected = []; + + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) + drop = Droppables.findDeepestChild(affected); + + if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); + if (drop) { + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + if (drop != this.last_active) Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) { + this.last_active.onDrop(element, this.last_active.element, event); + return true; + } + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +}; + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +}; + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create({ + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || { }); + + this.element = $(element); + + if(options.handle && Object.isString(options.handle)) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(!Object.isUndefined(Draggable._dragging[this.element]) && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if((tag_name = src.tagName.toUpperCase()) && ( + tag_name=='INPUT' || + tag_name=='SELECT' || + tag_name=='OPTION' || + tag_name=='BUTTON' || + tag_name=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = Position.cumulativeOffset(this.element); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + if(!this.delta) + this.delta = this.currentDelta(); + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); + if (!this._originallyAbsolute) + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + + if(!this.options.quiet){ + Position.prepare(); + Droppables.show(pointer, this.element); + } + + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(Prototype.Browser.WebKit) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.quiet){ + Position.prepare(); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + Droppables.show(pointer, this.element); + } + + if(this.options.ghosting) { + if (!this._originallyAbsolute) + Position.relativize(this.element); + delete this._originallyAbsolute; + Element.remove(this._clone); + this._clone = null; + } + + var dropped = false; + if(success) { + dropped = Droppables.fire(event, this.element); + if (!dropped) dropped = false; + } + if(dropped && this.options.onDropped) this.options.onDropped(this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && Object.isFunction(revert)) revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + if (dropped == 0 || revert != 'failure') + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = Position.cumulativeOffset(this.element); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(Object.isFunction(this.options.snap)) { + p = this.options.snap(p[0],p[1],this); + } else { + if(Object.isArray(this.options.snap)) { + p = p.map( function(v, i) { + return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)); + } else { + p = p.map( function(v) { + return (v/this.options.snap).round()*this.options.snap }.bind(this)); + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight; + } + } + return { top: T, left: L, width: W, height: H }; + } +}); + +Draggable._dragging = { }; + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create({ + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +}); + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: { }, + + _findRootElement: function(element) { + while (element.tagName.toUpperCase() != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + element = $(element); + var s = Sortable.sortables[element.id]; + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + + // these take arrays of elements or ids and can be + // used for better initialization performance + elements: false, + handles: false, + + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || { }); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + quiet: options.quiet, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + }; + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + }; + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (options.elements || this.findElements(element, options) || []).each( function(e,i) { + var handle = options.handles ? $(options.handles[i]) : + (options.handle ? $(e).select('.' + options.handle)[0] : e); + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.id] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = Position.cumulativeOffset(dropon); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + }; + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child); + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || { }); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + }; + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || { }); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || { }); + + var nodeMap = { }; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || { }); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +}; + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +}; + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +}; + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +}; \ No newline at end of file diff --git a/js/src/effects.js b/js/src/effects.js new file mode 100644 index 0000000..f31a81a --- /dev/null +++ b/js/src/effects.js @@ -0,0 +1,1130 @@ +// script.aculo.us effects.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008 + +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if (this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if (this.slice(0,1) == '#') { + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if (this.length==7) color = this.toLowerCase(); + } + } + return (color.length==7 ? color : (arguments[0] || this)); +}; + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +}; + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +}; + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if (Prototype.Browser.WebKit) window.scrollBy(0,0); + return element; +}; + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +}; + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + Transitions: { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + .5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; + return pos > 1 ? 1 : pos; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; + }, + pulse: function(pos, pulses) { + return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; + }, + spring: function(pos) { + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } + }, + DefaultOptions: { + duration: 1.0, // seconds + fps: 100, // 100= assume 66fps max. + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' + }, + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if (child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + new Element('span', {style: tagifyStyle}).update( + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if (((typeof element == 'object') || + Object.isFunction(element)) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || { }); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + var options = Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, arguments[2] || { }); + Effect[element.visible() ? + Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); + } +}; + +Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(Enumerable, { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = Object.isString(effect.options.queue) ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if (!this.interval) + this.interval = setInterval(this.loop.bind(this), 15); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if (this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + for(var i=0, len=this.effects.length;i= this.startOn) { + if (timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if (this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / this.totalTime, + frame = (pos * this.totalFrames).round(); + if (frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + cancel: function() { + if (!this.options.sync) + Effect.Queues.get(Object.isString(this.options.queue) ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if (this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if (!Object.isFunction(this[property])) data.set(property, this[property]); + return '#'; + } +}); + +Effect.Parallel = Class.create(Effect.Base, { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if (effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Tween = Class.create(Effect.Base, { + initialize: function(object, from, to) { + object = Object.isString(object) ? $(object) : object; + var args = $A(arguments), method = args.last(), + options = args.length == 5 ? args[3] : null; + this.method = Object.isFunction(method) ? method.bind(object) : + Object.isFunction(object[method]) ? object[method].bind(object) : + function(value) { object[method] = value }; + this.start(Object.extend({ from: from, to: to }, options || { })); + }, + update: function(position) { + this.method(position); + } +}); + +Effect.Event = Class.create(Effect.Base, { + initialize: function() { + this.start(Object.extend({ duration: 0 }, arguments[0] || { })); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || { }); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if (this.options.mode == 'absolute') { + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: (this.options.x * position + this.originalLeft).round() + 'px', + top: (this.options.y * position + this.originalTop).round() + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); +}; + +Effect.Scale = Class.create(Effect.Base, { + initialize: function(element, percent) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or { } with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || { }); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = { }; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if (fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if (this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if (/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if (!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if (this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = { }; + if (this.options.scaleX) d.width = width.round() + 'px'; + if (this.options.scaleY) d.height = height.round() + 'px'; + if (this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if (this.elementPositioning == 'absolute') { + if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if (this.options.scaleY) d.top = -topd + 'px'; + if (this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if (this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { }; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if (!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if (!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = function(element) { + var options = arguments[1] || { }, + scrollOffsets = document.viewport.getScrollOffsets(), + elementOffsets = $(element).cumulativeOffset(); + + if (options.offset) elementOffsets[1] += options.offset; + + return new Effect.Tween(null, + scrollOffsets.top, + elementOffsets[1], + options, + function(p){ scrollTo(scrollOffsets.left, p.round()); } + ); +}; + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if (effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + } + }, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || { }) + ); +}; + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || { }) + ); +}; + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || { })); +}; + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }); + } + }, arguments[1] || { })); +}; + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || { })); +}; + +Effect.Shake = function(element) { + element = $(element); + var options = Object.extend({ + distance: 20, + duration: 0.5 + }, arguments[1] || {}); + var distance = parseFloat(options.distance); + var split = parseFloat(options.duration) / 10.0; + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}); }}); }}); }}); }}); }}); +}; + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || { }) + ); +}; + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); + } + }, arguments[1] || { }) + ); +}; + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +}; + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ); + } + }); +}; + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +}; + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || { }, + oldOpacity = element.getInlineOpacity(), + transition = options.transition || Effect.Transitions.linear, + reverser = function(pos){ + return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); + }; + + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +}; + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || { })); +}; + +Effect.Morph = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: { } + }, arguments[1] || { }); + + if (!Object.isString(options.style)) this.style = $H(options.style); + else { + if (options.style.include(':')) + this.style = options.style.parseStyle(); + else { + this.element.addClassName(options.style); + this.style = $H(this.element.getStyles()); + this.element.removeClassName(options.style); + var css = this.element.getStyles(); + this.style = this.style.reject(function(style) { + return style.value == css[style.key]; + }); + options.afterFinishInternal = function(effect) { + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + effect.element.style[transform.style] = ''; + }); + }; + } + } + this.start(options); + }, + + setup: function(){ + function parseColor(color){ + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ); + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0], value = pair[1], unit = null; + + if (value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if (property == 'opacity') { + value = parseFloat(value); + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if (Element.CSS_LENGTH.test(value)) { + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); + value = parseFloat(components[1]); + unit = (components.length == 3) ? components[2] : null; + } + + var originalValue = this.element.getStyle(property); + return { + style: property.camelize(), + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }; + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ); + }); + }, + update: function(position) { + var style = { }, transform, i = this.transforms.length; + while(i--) + style[(transform = this.transforms[i]).style] = + transform.unit=='color' ? '#'+ + (Math.round(transform.originalValue[0]+ + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + + (Math.round(transform.originalValue[1]+ + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + + (Math.round(transform.originalValue[2]+ + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : + (transform.originalValue + + (transform.targetValue - transform.originalValue) * position).toFixed(3) + + (transform.unit === null ? '' : transform.unit); + this.element.setStyle(style, true); + } +}); + +Effect.Transform = Class.create({ + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || { }; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + track = $H(track); + var data = track.values().first(); + this.tracks.push($H({ + ids: track.keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); + var elements = [$(ids) || $$(ids)].flatten(); + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.__parseStyleElement = document.createElement('div'); +String.prototype.parseStyle = function(){ + var style, styleRules = $H(); + if (Prototype.Browser.WebKit) + style = new Element('div',{style:this}).style; + else { + String.__parseStyleElement.innerHTML = '
    '; + style = String.__parseStyleElement.childNodes[0].style; + } + + Element.CSS_PROPERTIES.each(function(property){ + if (style[property]) styleRules.set(property, style[property]); + }); + + if (Prototype.Browser.IE && this.include('opacity')) + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); + + return styleRules; +}; + +if (document.defaultView && document.defaultView.getComputedStyle) { + Element.getStyles = function(element) { + var css = document.defaultView.getComputedStyle($(element), null); + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { + styles[property] = css[property]; + return styles; + }); + }; +} else { + Element.getStyles = function(element) { + element = $(element); + var css = element.currentStyle, styles; + styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { + results[property] = css[property]; + return results; + }); + if (!styles.opacity) styles.opacity = element.getOpacity(); + return styles; + }; +} + +Effect.Methods = { + morph: function(element, style) { + element = $(element); + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); + return element; + }, + visualEffect: function(element, effect, options) { + element = $(element); + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[klass](element, options); + return element; + }, + highlight: function(element, options) { + element = $(element); + new Effect.Highlight(element, options); + return element; + } +}; + +$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ + 'pulsate shake puff squish switchOff dropOut').each( + function(effect) { + Effect.Methods[effect] = function(element, options){ + element = $(element); + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); + return element; + }; + } +); + +$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( + function(f) { Effect.Methods[f] = Element[f]; } +); + +Element.addMethods(Effect.Methods); \ No newline at end of file diff --git a/js/src/scriptaculous.js b/js/src/scriptaculous.js new file mode 100644 index 0000000..3e5543b --- /dev/null +++ b/js/src/scriptaculous.js @@ -0,0 +1,60 @@ +// script.aculo.us scriptaculous.js v1.8.2, Tue Nov 18 18:30:58 +0100 2008 + +// Copyright (c) 2005-2008 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +var Scriptaculous = { + Version: '1.8.2', + require: function(libraryName) { + // inserting via DOM fails in Safari 2.0, so brute force approach + document.write(' diff --git a/onyx2/modules/templates/smarty/plugins/block.php.php b/onyx2/modules/templates/smarty/plugins/block.php.php new file mode 100644 index 0000000..8fedd8b --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/block.php.php @@ -0,0 +1,27 @@ +allow_php_tag) { + throw new SmartyException("{php} is deprecated, set allow_php_tag = true to enable"); + } + eval($content); + return ''; +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/block.textformat.php b/onyx2/modules/templates/smarty/plugins/block.textformat.php new file mode 100644 index 0000000..517fd62 --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/block.textformat.php @@ -0,0 +1,102 @@ + + * Name: textformat
    + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings
    + * + * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array $params parameters + *
    + * Params:   style: string (email)
    + *            indent: integer (0)
    + *            wrap: integer (80)
    + *            wrap_char string ("\n")
    + *            indent_char: string (" ")
    + *            wrap_boundary: boolean (true)
    + * 
    + * @author Monte Ohrt + * @param string $content contents of the block + * @param object $template template object + * @param boolean &$repeat repeat flag + * @return string content re-formatted + */ +function smarty_block_textformat($params, $content, $template, &$repeat) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + // split into paragraphs + $_paragraphs = preg_split('![\r\n][\r\n]!', $content); + $_output = ''; + + for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { + if ($_paragraphs[$_x] == '') { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraphs[$_x] = preg_replace(array('!\s+!', '!(^\s+)|(\s+$)!'), array(' ', ''), $_paragraphs[$_x]); + // indent first line + if ($indent_first > 0) { + $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; + } + // wordwrap sentences + $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if ($indent > 0) { + $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); + } + } + $_output = implode($wrap_char . $wrap_char, $_paragraphs); + + return $assign ? $template->assign($assign, $_output) : $_output; +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/function.counter.php b/onyx2/modules/templates/smarty/plugins/function.counter.php new file mode 100644 index 0000000..7c50bd4 --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/function.counter.php @@ -0,0 +1,78 @@ + + * Name: counter
    + * Purpose: print out a counter value + * @author Monte Ohrt + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array parameters + * @param Smarty + * @param object $template template object + * @return string|null + */ +function smarty_function_counter($params, $template) +{ + static $counters = array(); + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $template->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/function.cycle.php b/onyx2/modules/templates/smarty/plugins/function.cycle.php new file mode 100644 index 0000000..98e3e28 --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/function.cycle.php @@ -0,0 +1,106 @@ + + * Name: cycle
    + * Date: May 3, 2002
    + * Purpose: cycle through given values
    + * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * + * Examples:
    + *
    + * {cycle values="#eeeeee,#d0d0d0d"}
    + * {cycle name=row values="one,two,three" reset=true}
    + * {cycle name=row}
    + * 
    + * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt + * @author credit to Mark Priatel + * @author credit to Gerard + * @author credit to Jason Sweat + * @version 1.3 + * @param array + * @param object $template template object + * @return string|null + */ + +function smarty_function_cycle($params, $template) +{ + static $cycle_vars; + + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!in_array('values', array_keys($params))) { + if(!isset($cycle_vars[$name]['values'])) { + trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $params['values'] ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $params['values']; + } + + if (isset($params['delimiter'])) { + $cycle_vars[$name]['delimiter'] = $params['delimiter']; + } elseif (!isset($cycle_vars[$name]['delimiter'])) { + $cycle_vars[$name]['delimiter'] = ','; + } + + if(is_array($cycle_vars[$name]['values'])) { + $cycle_array = $cycle_vars[$name]['values']; + } else { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $template->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/function.fetch.php b/onyx2/modules/templates/smarty/plugins/function.fetch.php new file mode 100644 index 0000000..2b09fb9 --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/function.fetch.php @@ -0,0 +1,216 @@ + + * Name: fetch
    + * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt + * @param array $params parameters + * @param object $template template object + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, $template) +{ + if (empty($params['file'])) { + trigger_error("[plugin] fetch parameter 'file' cannot be empty",E_USER_NOTICE); + return; + } + + $content = ''; + if (isset($template->security_policy) && !preg_match('!^(http|ftp)://!i', $params['file'])) { + if(!$template->security_policy->isTrustedResourceDir($params['file'])) { + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + trigger_error('[plugin] fetch cannot read file \'' . $params['file'] . '\'',E_USER_NOTICE); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$template->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(!empty($uri_parts['user'])) { + $user = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + trigger_error("[plugin] invalid header format '".$param_value."'",E_USER_NOTICE); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + trigger_error("[plugin] invalid value for attribute '".$param_key."'",E_USER_NOTICE); + return; + } + break; + default: + trigger_error("[plugin] unrecognized attribute '".$param_key."'",E_USER_NOTICE); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + trigger_error("[plugin] unable to fetch: $errstr ($errno)",E_USER_NOTICE); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = preg_split("!\r\n\r\n!",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $template->assign($params['assign_headers'],preg_split("!\r\n!",$csplit[0])); + } + } + } else { + trigger_error("[plugin fetch] unable to parse URL, check syntax",E_USER_NOTICE); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + trigger_error('[plugin] fetch cannot read file \'' . $params['file'] .'\'',E_USER_NOTICE); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $template->assign($params['assign'],$content); + } else { + return $content; + } +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/function.html_checkboxes.php b/onyx2/modules/templates/smarty/plugins/function.html_checkboxes.php new file mode 100644 index 0000000..6a1a3ff --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/function.html_checkboxes.php @@ -0,0 +1,143 @@ + + * Type: function
    + * Name: html_checkboxes
    + * Date: 24.Feb.2003
    + * Purpose: Prints out a list of checkbox input types
    + * Examples: + *
    + * {html_checkboxes values=$ids output=$names}
    + * {html_checkboxes values=$ids name='box' separator='
    ' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='
    ' output=$names} + *
    + * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme + * @author credits to Monte Ohrt + * @version 1.0 + * @param array $params parameters + * Input:
    + * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie
    or   + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * @param object $template template object + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, $template) +{ + require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_map('strval', array_values((array)$_val)); + break; + + case 'checkboxes': + trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = array(); + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + if(!empty($params['assign'])) { + $template->assign($params['assign'], $_html_result); + } else { + return implode("\n",$_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= ''; + $_output .= $separator; + + return $_output; +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/function.html_image.php b/onyx2/modules/templates/smarty/plugins/function.html_image.php new file mode 100644 index 0000000..abb7b57 --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/function.html_image.php @@ -0,0 +1,137 @@ + + * Name: html_image
    + * Date: Feb 24, 2003
    + * Purpose: format HTML tags for the image
    + * Examples: {html_image file="/images/masthead.gif"} + * Output: + * + * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt + * @author credits to Duda + * @version 1.0 + * @param array $params parameters + * Input:
    + * - file = file (and path) of image (required) + * - height = image height (optional, default actual height) + * - width = image width (optional, default actual width) + * - basedir = base directory for absolute paths, default + * is environment variable DOCUMENT_ROOT + * - path_prefix = prefix for path output (optional, default empty) + * @param object $template template object + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_image($params, $template) +{ + require_once(SMARTY_PLUGINS_DIR . 'shared.escape_special_chars.php'); + + $alt = ''; + $file = ''; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $path_prefix = ''; + $server_vars = $_SERVER; + $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; + foreach($params as $_key => $_val) { + switch ($_key) { + case 'file': + case 'height': + case 'width': + case 'dpi': + case 'path_prefix': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if (!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = ''; + $suffix = ''; + break; + + default: + if (!is_array($_val)) { + $extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"'; + } else { + throw new SmartyException ("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file, 0, 1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if (!isset($params['width']) || !isset($params['height'])) { + if (!$_image_data = @getimagesize($_image_path)) { + if (!file_exists($_image_path)) { + trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if (!is_readable($_image_path)) { + trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + if (isset($template->security_policy)) { + if (!$template->security_policy->isTrustedResourceDir($_image_path)) { + return; + } + } + + if (!isset($params['width'])) { + $width = $_image_data[0]; + } + if (!isset($params['height'])) { + $height = $_image_data[1]; + } + } + + if (isset($params['dpi'])) { + if (strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + $_resize = $dpi_default / $params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . '' . $alt . '' . $suffix; +} + +?> \ No newline at end of file diff --git a/onyx2/modules/templates/smarty/plugins/function.html_options.php b/onyx2/modules/templates/smarty/plugins/function.html_options.php new file mode 100644 index 0000000..7ac0390 --- /dev/null +++ b/onyx2/modules/templates/smarty/plugins/function.html_options.php @@ -0,0 +1,133 @@ + + * Name: html_options
    + * Purpose: Prints the list of