X-Git-Url: http://git.euphorik.ch/?p=euphorik.git;a=blobdiff_plain;f=js%2Feuphorik.js;h=afe0251e7da2334b843588c58c77a5bcf00a2d96;hp=b93498f7e071632aa33f29f58ffb404a20d2b6f4;hb=d1dff528ecf8ace680f8ba92d11b09e84fd6ff2f;hpb=7fb422d6d4a7a59c8f74d938371a4a10474e8ea4 diff --git a/js/euphorik.js b/js/euphorik.js index b93498f..afe0251 100755 --- a/js/euphorik.js +++ b/js/euphorik.js @@ -26,7 +26,7 @@ // tout euphorik est contenu dans cet objet var euphorik = {} // ;; euphorik.include = -// ;; euphorik.include = function(f) { var s = document.createElement('script'); s.type = 'text/javascript'; s.src = "js/" + f + ".js"; document.getElementsByTagName('head')[0].appendChild(s); } + //;; euphorik.include = function(f) { var s = document.createElement('script'); s.type = 'text/javascript'; s.src = "js/" + f + ".js"; document.getElementsByTagName('head')[0].appendChild(s); } // version jQuery : function(f) { jQuery.ajax({async : false, url : "js/" + f + ".js", dataType : "script"}) } @@ -34,43 +34,72 @@ var euphorik = {} ;; euphorik.include = function(f) { ;; var req, url = 'js/' + f + '.js' ;; if (window.XMLHttpRequest) { -;; req = new XMLHttpRequest(); req.open("GET", url, false /* async */); req.send(null); +;; req = new XMLHttpRequest(); req.open("GET", url, false); req.send(null); ;; } else if (window.ActiveXObject) { ;; req = new ActiveXObject((navigator.userAgent.toLowerCase().indexOf('msie 5') != -1) ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP"); ;; if (req) { req.open("GET", url, false); req.send(); } ;; } ;; if (req!==false) { if (req.status==200) { window.eval(req.responseText); } else if (req.status==404) { alert("erreur de chargement (404) de : " + url) } } -;; } - -;; euphorik.include("jquery") -;; euphorik.include("jquery.lightbox") -;; euphorik.include("md5") -;; euphorik.include("json2") - -;; euphorik.include("conf") -;; euphorik.include("util") -;; euphorik.include("formateur") -;; euphorik.include("pages") - -;; euphorik.include("pageMinichat") -;; euphorik.include("pageAdmin") -;; euphorik.include("pageProfile") -;; euphorik.include("pageRegister") -;; euphorik.include("pageAbout") - +;; }; + +;; euphorik.include("jquery"); +;; euphorik.include("jquery.lightbox"); +;; euphorik.include("md5"); +;; euphorik.include("json2"); +;; euphorik.include("comet"); + +;; euphorik.include("conf"); +;; euphorik.include("util"); +;; euphorik.include("formateur"); +;; euphorik.include("pages"); +;; euphorik.include("client"); + +;; euphorik.include("pageMinichat/pageMinichat"); +;; euphorik.include("pageMinichat/conversation"); +;; euphorik.include("pageMinichat/conversations"); +;; euphorik.include("pageMinichat/message"); +;; euphorik.include("pageMinichat/commandes"); +;; euphorik.include("pageAdmin"); +;; euphorik.include("pageProfile"); +;; euphorik.include("pageRegister"); +;; euphorik.include("pageAbout"); + +// tout un tas d'améliorations de JavaScript ;) +/** + * Pour chaque propriété de l'objet execute f(p, v) ou p est le nom de la propriété et v sa valeur. + * Ne parcours pas les propriétés des prototypes. + * FIXME : Normalement : Object.prototype.each = function(f) mais non supporté par jquery + */ +//Object.prototype.each = function(f) { +var objectEach = function(o, f) { + for (var k in o) { + if (o.hasOwnProperty(k)) { + f(k, o[k]); + } + } +}; -// tout un tas d'améliorations des objets javascript ;) -/** - * Pour chaque propriété de l'objet execute f(p, v) ou p est le nom de la propriété et v sa valeur. - * Ne parcours pas les propriétés des prototypes. - */ -object.prototype.each = function(f) { - for (var b in boutons) { - if (boutons.hasOwnProperty(b)) { - f(b, boutons[b]) +var objectMemberCount = function(o) { + var nb = 0; + for (var k in o) { + if (o.hasOwnProperty(k)) { + nb += 1; } } -} + return nb; +}; + +Array.prototype.each = function(f) { + for (var i = 0; i < this.length; i++) { + f(i, this[i]); + } +}; + +Array.prototype.map = function(f) { + for (var i = 0; i < this.length; i++) { + this[i] = f(this[i]) + } +}; String.prototype.trim = function() { return jQuery.trim(this) // anciennement : this.replace(/^\s+|\s+$/g, ""); @@ -85,621 +114,33 @@ String.prototype.rtrim = function() { } -/////////////////////////////////////////////////////////////////////////////////////////////////// - -// les statuts possibes du client -var statutType = { - // mode enregistré, peut poster des messages et modifier son profile - auth_registered : 0, - // mode identifié, peut poster des messages mais n'a pas accès au profile - auth_not_registered : 1, - // mode déconnecté, ne peut pas poster de message - deconnected : 2 -} - -function Client(util) -{ - this.util = util - - this.cookie = null - this.regexCookie = new RegExp("^cookie=([^;]*)") - - // données personnels - this.resetDonneesPersonnelles() - - this.setStatut(statutType.deconnected) - - // si true alors chaque modification du client est mémorisé sur le serveur - this.autoflush = $.browser["opera"] -} - -Client.prototype.resetDonneesPersonnelles = function() -{ - this.id = 0 - this.pseudo = euphorik.conf.pseudoDefaut - this.login = "" - this.password = "" - this.email = "" - this.css = $("link#cssPrincipale").attr("href") - this.chatOrder = "reverse" - this.nickFormat = "nick" - this.viewTimes = true - this.viewTooltips = true - this.cookie = undefined - - this.pagePrincipale = 1 - this.ekMaster = false - this.ostentatiousMaster = "light" - - // les conversations, une conversation est un objet possédant les attributs suivants : - // - root (entier) - // - page (entier) - // - reduit (bool) - this.conversations = [] -} - -Client.prototype.setCss = function(css) -{ - if (this.css == css || css == "") - return - - this.css = css - $("link#cssPrincipale").attr("href", this.css) - if (this.autoflush) this.flush(true) -} - -Client.prototype.pageSuivante = function(numConv) -{ - if (numConv < 0 && this.pagePrincipale > 1) - this.pagePrincipale -= 1 - else if (this.conversations[numConv].page > 1) - this.conversations[numConv].page -= 1 -} - -Client.prototype.pagePrecedente = function(numConv) -{ - if (numConv < 0) - this.pagePrincipale += 1 - else - this.conversations[numConv].page += 1 -} - -/** - * Définit la première page pour la conversation donnée. - * @return true si la page a changé sinon false - */ -Client.prototype.goPremierePage = function(numConv) -{ - if (numConv < 0) - { - if (this.pagePrincipale == 1) - return false - this.pagePrincipale = 1 - } - else - { - if (this.conversations[numConv].page == 1) - return false - this.conversations[numConv].page = 1 - } - return true -} - -/** - * Ajoute une conversation à la vue de l'utilisateur. - * Le profile de l'utilisateur est directement sauvegardé sur le serveur. - * @param racines la racine de la conversation (integer) - * @return true si la conversation a été créée sinon false (par exemple si la conv existe déjà) - */ -Client.prototype.ajouterConversation = function(racine) -{ - // vérification s'il elle n'existe pas déjà - for (var i = 0; i < this.conversations.length; i++) - if (this.conversations[i].root == racine) - return false - - this.conversations.push({root : racine, page : 1, reduit : false}) - if (this.autoflush) this.flush(true) - - return true -} - -Client.prototype.supprimerConversation = function(num) -{ - if (num < 0 || num >= this.conversations.length) return - - // décalage TODO : supprimer le dernier élément - for (var i = num; i < this.conversations.length - 1; i++) - this.conversations[i] = this.conversations[i+1] - this.conversations.pop() - - if (this.autoflush) this.flush(true) -} - -Client.prototype.getJSONLogin = function(login, password) -{ - return { - "header" : { "action" : "authentification", "version" : euphorik.conf.versionProtocole }, - "login" : login, - "password" : password - } -} - -Client.prototype.getJSONLoginCookie = function() -{ - return { - "header" : { "action" : "authentification", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.cookie - } -} - /** - * le couple (login, password) est facultatif. S'il n'est pas fournit alors il ne sera pas possible - * de s'autentifier avec (login, password). + * Voir : http://www.coolpage.com/developer/javascript/Correct%20OOP%20for%20Javascript.html + * + * Exemple : + * + * function Mammal(name) { + * this.name = name; + * } + * + * Cat.Inherits(Mammal); + * function Cat(name) { + * this.Super(Mammal, name); + * } */ -Client.prototype.getJSONEnregistrement = function(login, password) -{ - var mess = { "header" : { "action" : "register", "version" : euphorik.conf.versionProtocole }} - - if (login != undefined && password != undefined) - { - mess["login"] = login - mess["password"] = password +/*Object.prototype.Super = function(parent) { + if(arguments.length > 1) { + parent.apply( this, Array.prototype.slice.call( arguments, 1 ) ); + } else { + parent.call( this ); } - - return mess; } +Function.prototype.Inherits = function(parent) { + this.prototype = new parent(); + this.prototype.constructor = this; +}*/ -Client.prototype.getJSONConversations = function() -{ - var conversations = new Array() - for (var i = 0; i < this.conversations.length; i++) - conversations.push({root : this.conversations[i].root, minimized : this.conversations[i].reduit}) - return conversations -} -Client.prototype.getJSONProfile = function() -{ - return { - "header" : { "action" : "set_profile", "version" : euphorik.conf.versionProtocole }, - "cookie" : this.cookie, - "login" : this.login, - "password" : this.password, - "nick" : this.pseudo, - "email" : this.email, - "css" : this.css, - "chat_order" : this.chatOrder, - "nick_format" : this.nickFormat, - "view_times" : this.viewTimes, - "view_tooltips" : this.viewTooltips, - "conversations" : this.getJSONConversations(), - "ostentatious_master" : this.ostentatiousMaster - } -} - -/** - * Renvoie null si pas définit. - */ -Client.prototype.getCookie = function() -{ - var cookie = this.regexCookie.exec(document.cookie) - if (cookie == null) this.cookie = null - else this.cookie = cookie[1] -} - -Client.prototype.delCookie = function() -{ - document.cookie = "cookie=; max-age=0" -} - -Client.prototype.setCookie = function() -{ - if (this.cookie == null || this.cookie == undefined) - return - - // ne fonctionne pas sous IE.... - /*document.cookie = "cookie=" + this.cookie + "; max-age=" + (60 * 60 * 24 * 365) */ - - document.cookie = - "cookie="+this.cookie+"; expires=" + new Date(new Date().getTime() + 1000 * 60 * 60 * 24 * 365).toUTCString() -} - -Client.prototype.authentifie = function() -{ - return this.statut == statutType.auth_registered || this.statut == statutType.auth_not_registered -} - -Client.prototype.setStatut = function(statut) -{ - // conversation en "enum" si en "string" - if (typeof(statut) == "string") - { - statut = - statut == "auth_registered" ? - statutType.auth_registered : - (statut == "auth_not_registered" ? statutType.auth_not_registered : statutType.deconnected) - } - - if (statut == this.statut) return - - this.statut = statut - this.majMenu() - this.majLogo() -} - -/** - * Effectue la connexion vers le serveur. - * Cette fonction est bloquante tant que la connexion n'a pas été établie. - * S'il existe un cookie en local on s'authentifie directement avec lui. - * Si il n'est pas possible de s'authentifier alors on affiche un captcha anti-bot. - */ -Client.prototype.connexionCookie = function() -{ - this.getCookie() - if (this.cookie == null) return false; - return this.connexion(this.getJSONLoginCookie()) -} - -Client.prototype.connexionLogin = function(login, password) -{ - return this.connexion(this.getJSONLogin(login, password)) -} - -Client.prototype.enregistrement = function(login, password) -{ - if (this.authentifie()) - { - this.login = login - this.password = password - if(this.flush()) - { - this.setStatut(statutType.auth_registered) - return true - } - return false - } - else - { - return this.connexion(this.getJSONEnregistrement(login, password)) - } -} - -/** - * Connexion. Réalisé de manière synchrone. - */ -Client.prototype.connexion = function(messageJson) -{ - var thisClient = this - jQuery.ajax( - { - async: false, - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(messageJson), - success: - function(data) - { - if (data["reply"] == "error") - { - thisClient.util.messageDialogue(data["error_message"]) - // suppression du cookie actuel, cas où le cookie du client ne permet pas une authentification - thisClient.delCookie() - } - else - thisClient.chargerDonnees(data) - } - } - ) - return this.authentifie() -} - -Client.prototype.deconnexion = function() -{ - this.flush(true) - this.delCookie() - this.resetDonneesPersonnelles() - this.setStatut(statutType.deconnected) // deconnexion -} - -Client.prototype.chargerDonnees = function(data) -{ - // la modification du statut qui suit met à jour le menu, le menu dépend (page admin) - // de l'état ekMaster - this.ekMaster = data["ek_master"] != undefined ? data["ek_master"] : false - - this.setStatut(data["status"]) - - if (this.authentifie()) - { - this.cookie = data["cookie"] - this.setCookie() - - this.id = data["id"] - this.login = data["login"] - this.pseudo = data["nick"] - this.email = data["email"] - this.setCss(data["css"]) - this.chatOrder = data["chat_order"] - this.nickFormat = data["nick_format"] - this.viewTimes = data["view_times"] - this.viewTooltips = data["view_tooltips"] - this.ostentatiousMaster = data["ostentatious_master"] - - // la page de la conversation principale - this.pagePrincipale = 1 - - // les conversations - this.conversations = data["conversations"] - for (var i = 0; i < this.conversations.length; i++) - this.conversations[i] = {root : this.conversations[i].root, page : 1, reduit : this.conversations[i].minimized} - - this.majBulle() - this.majCssSelectionee() - //this.majLogo() - } -} - -/** - * Met à jour les données personne sur serveur. - * @param async de manière asynchrone ? défaut = true - * @return false si le flush n'a pas pû se faire sinon true - */ -Client.prototype.flush = function(async) -{ - if (async == undefined) - async = false - - if (!this.authentifie()) - return false - - var thisClient = this - var ok = true - jQuery.ajax( - { - async: async, - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction(this.getJSONProfile()), - success: - function(data) - { - if (data["reply"] == "error") - { - thisClient.util.messageDialogue(data["error_message"]) - ok = false - } - else - { - thisClient.majBulle() - } - } - } - ) - - return ok -} - -Client.prototype.majMenu = function() -{ - var displayType = "block" - - $("#menu .admin").css("display", this.ekMaster ? displayType : "none") - - // met à jour le menu - if (this.statut == statutType.auth_registered) - { - $("#menu .profile").css("display", displayType).text("profile") - $("#menu .logout").css("display", displayType) - $("#menu .register").css("display", "none") - } - else if (this.statut == statutType.auth_not_registered) - { - $("#menu .profile").css("display", "none") - $("#menu .logout").css("display", displayType) - $("#menu .register").css("display", displayType) - } - else - { - $("#menu .profile").css("display", displayType).text("login") - $("#menu .logout").css("display", "none") - $("#menu .register").css("display", displayType) - } -} - -/** - * Met à jour l'affichage des infos bulles en fonction du profile. - */ -Client.prototype.majBulle = function() -{ - this.util.bulleActive = this.viewTooltips -} - -/** - * Met à jour la css sélectionnée, lors du chargement des données. - */ -Client.prototype.majCssSelectionee = function() -{ - // extraction du numéro de la css courante - var numCssCourante = this.css.match(/^.*?\/(\d)\/.*$/) - if (numCssCourante != null && numCssCourante[1] != undefined) - { - $("#menuCss option").removeAttr("selected") - $("#menuCss option[value=" + numCssCourante[1]+ "]").attr("selected", "selected") - } -} - -/** - * Change la "class" du logo en fonction du statut de ekMaster. - */ -Client.prototype.majLogo = function() -{ - if (this.ekMaster) - $("#logo").addClass("ekMaster") - else - $("#logo").removeClass("ekMaster") -} - - -Client.prototype.slap = function(userId, raison) -{ - var thisClient = this - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction( - { - "header" : { "action" : "slap", "version" : euphorik.conf.versionProtocole }, - "cookie" : thisClient.cookie, - "user_id" : userId, - "reason" : raison - }), - success: - function(data) - { - if (data["reply"] == "error") - thisClient.util.messageDialogue(data["error_message"]) - } - }) -} - -Client.prototype.ban = function(userId, raison, minutes) -{ - var thisClient = this - - // par défaut un ban correspond à 3 jours - if (typeof(minutes) == "undefined") - minutes = euphorik.conf.tempsBan; - - jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - data: this.util.jsonVersAction( - { - "header" : { "action" : "ban", "version" : euphorik.conf.versionProtocole }, - "cookie" : thisClient.cookie, - "duration" : minutes, - "user_id" : userId, - "reason" : raison - }), - success: - function(data) - { - if (data["reply"] == "error") - thisClient.util.messageDialogue(data["error_message"]) - } - }) -} - -Client.prototype.kick = function(userId, raison) -{ - this.ban(userId, raison, euphorik.conf.tempsKick) -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * classe permettant de gérer les événements (push serveur). - * l'information envoyé est sous la forme : - * { - * "header" : {"action" : "wait_event", "version" : }, - * "page" : - * [..] - * } - * l'information reçu est sous la forme : - * { - * "reply" : - * } - * @page la page - */ -function PageEvent(page, util) -{ - this.page = page - this.util = util - - // l'objet JSONHttpRequest représentant la connexion d'attente - this.attenteCourante = null - - // le multhreading du pauvre, merci javascript de m'offrire autant de primitives pour la gestion de la concurrence... - this.stop = false -} - -/** - * Arrête l'attente courante s'il y en a une. - */ -PageEvent.prototype.stopAttenteCourante = function() -{ - this.stop = true - - if (this.attenteCourante != null) - { - this.attenteCourante.abort() - } -} - -/** - * Attend un événement lié à la page. - * @funSend une fonction renvoyant les données json à envoyer - * @funsReceive est un objet comprenant les fonctions à appeler en fonction du "reply" - * les fonctions acceptent un paramètre correspondant au données reçues. - * exemple : {"new_message" : function(data){ ... }} - */ -PageEvent.prototype.waitEvent = function(funSend, funsReceive) -{ - this.stopAttenteCourante() - - this.stop = false - - var thisPageEvent = this - - // on doit conserver l'ordre des valeurs de l'objet JSON (le serveur les veut dans l'ordre définit dans le protocole) - // TODO : ya pas mieux ? - var dataToSend = - { - "header" : { "action" : "wait_event", "version" : euphorik.conf.versionProtocole }, - "page" : this.page - } - var poulpe = funSend() - for (var v in poulpe) - dataToSend[v] = poulpe[v] - - this.attenteCourante = jQuery.ajax({ - type: "POST", - url: "request", - dataType: "json", - // TODO : doit disparaitre - timeout: 180000, // timeout de 3min. Gros HACK pas beau. FIXME problème décrit ici : http://groups.google.com/group/jquery-en/browse_thread/thread/8724e64af3333a76 - data: this.util.jsonVersAction(dataToSend), - success: - function(data) - { - funsReceive[data["reply"]](data) - - // rappel de la fonction dans 100 ms - setTimeout(function(){ thisPageEvent.waitEvent2(funSend, funsReceive) }, 100) - }, - error: - function(XMLHttpRequest, textStatus, errorThrown) - { - ;; console.log("Connexion perdue dans waitEvent") - setTimeout(function(){ thisPageEvent.waitEvent2(funSend, funsReceive) }, 1000) - } - }) -} - -/** - * Si un stopAttenteCourante survient un peu n'importe quand il faut imédiatement arreter de boucler. - */ -PageEvent.prototype.waitEvent2 = function(funSend, funsReceive) -{ - if (this.stop) - return - this.waitEvent(funSend, funsReceive) -} /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -707,12 +148,13 @@ PageEvent.prototype.waitEvent2 = function(funSend, funsReceive) // le main $(document).ready( function() - { + { var formateur = new euphorik.Formateur() - var util = new euphorik.Util(formateur) - var client = new Client(util) + var util = new euphorik.Util(formateur) + var client = new euphorik.Client(util) var pages = new euphorik.Pages() + // connexion vers le serveur (utilise un cookie qui traine) client.connexionCookie() @@ -742,11 +184,11 @@ $(document).ready( // TODO : simplifier et pouvoir créer des liens par exemple : Conditions d'utilisation $("#footer .conditions").click(function(){ pages.afficherPage("conditions_utilisation") }) - pages.ajouterPage(new PageMinichat(client, formateur, util)) - pages.ajouterPage(new PageAdmin(client, formateur, util)) - pages.ajouterPage(new PageProfile(client, formateur, util)) - pages.ajouterPage(new PageRegister(client, formateur, util)) - pages.ajouterPage(new PageAbout(client, formateur, util)) + pages.ajouterPage(new euphorik.PageMinichat(client, formateur, util)) + pages.ajouterPage(new euphorik.PageAdmin(client, formateur, util)) + pages.ajouterPage(new euphorik.PageProfile(client, formateur, util)) + pages.ajouterPage(new euphorik.PageRegister(client, formateur, util)) + pages.ajouterPage(new euphorik.PageAbout(client, formateur, util)) pages.ajouterPage("conditions_utilisation") pages.afficherPage("minichat")