background-repeat: no-repeat;\r
background-position: 5px 2px;\r
vertical-align: top;\r
+}
+
+#page.minichat #conversations .conversation {
+ border-width: 2px;
+ border-style: solid;
+ border-color: white
}\r
-#page.minichat #messages div.message { \r
+#page.minichat #conversations div.message { \r
border-left-width: 5px;\r
border-left-style: solid;\r
border-color: transparent;
cursor: pointer;
}
\r
-#page.minichat #messages div.messageImpair {\r
+#page.minichat #conversations div.messageImpair {\r
background-color: #05002c;\r
}\r
\r
-#page.minichat #messages div.messagePair {\r
+#page.minichat #conversations div.messagePair {\r
background-color: #080047;\r
}
\r
/* Il n'y a plus de mise en evidence
-#page.minichat #messages div.miseEnEvidenceReponse {
+#page.minichat #conversations div.miseEnEvidenceReponse {
background-color: #bd7a11;
}
-#page.minichat #messages div.miseEnEvidenceCourant {
+#page.minichat #conversations div.miseEnEvidenceCourant {
background-color: #bd1129;
}
-#page.minichat #messages div.miseEnEvidenceConversation {
+#page.minichat #conversations div.miseEnEvidenceConversation {
background-color: #b711bd;
}*/\r
-#page.minichat #messages div.cache {
+#page.minichat #conversations div.cache {
opacity: 0.3;\r
\r
/* Hack IE 7 */ \r
zoom: 1
}
\r
-#page.minichat #messages div.reponse {\r
+#page.minichat #conversations div.reponse {\r
border-color: #bd7a11\r
}\r
-#page.minichat #messages div.repondu {\r
+#page.minichat #conversations div.repondu {\r
border-color: #b711bd \r
}\r
-#page.minichat #messages div.proprietaire {\r
+#page.minichat #conversations div.proprietaire {\r
border-color: #bd1129\r
}
-#page.minichat #messages div.systeme {
+#page.minichat #conversations div.systeme {
background-color: #555555
}\r
\r
height:100px;\r
}*/\r
-#page.minichat #messages .repondA {
+#page.minichat #conversations .repondA {
display: inline;
margin-left: 4px;
color: #bd7a11
}
\r
-#page.minichat #messages .contenu {\r
+#page.minichat #conversations .contenu {\r
display: inline;\r
+}
+
+#page.minichat #conversations .extraire {
+ float: right;
+ padding-right: 2px;
+ padding-left: 2px;
+ background-color: #4f5519;
+}
+
+#page.minichat #conversations .extraire:hover {
+ background-color: #818c27
}\r
\r
#page.minichat #pages {\r
[ok] Ne pas afficher la css dans le profile
[ok] Ne pas effacer le message (dans le <input>) si l'on recoit un "pas ok" lors de l'envoie
+* Conversations :
+ a) implémenter coté serveur et client la sauvegarde et la restauration des conversations
+ b) Supprimer l'envoie de la description des conversations lors du refresh ainsi que modifié la manière de créer les conversations (maj des diagrammes de séquence)
+ c) Navigation vers les pages précédentes
+ c) Mettre à jour l'HTML/CSS de chaque skin en fonction
* Utiliser une listbox pour la liste des css
* Ralentir volontairement le connexion lors d'un mauvais login (ou après n mauvais login)
* Pouvoir switcher entre un affichage "pseudo" ou "pseudo (login)"
[4] Bot de traduction
[4] Bot de jeu (jeu du pendu par exemple)
[4] RSS
+[4] Système de vote sur les messages, + ou - qui donne des points aux messages...
[4] Voir les personnes connectées
[4] Avoir une liste d'amis
[4] Restreindre la consultation d'un message posté à un ou plusieurs utilisateurs définis. Les messages de la conversation ne sont alors vus que par cet ensemble d'utilisateurs.
Rafraichissement:
* Le client envoie une demande au serveur avec l'id du dernier message (via XMLHttpRequest ou un function de JQuery)
* Le serveur maintient la connexion bloqué si le client est à jour.
- * Dès qu'un nouveau message arrive, le serveurs débloque la connexion est envoie le ou les messages manquants.
+ * Dès qclientu'un nouveau message arrive, le serveurs débloque la connexion est envoie le ou les messages manquants.
C. Protocole
<login>paul49</login>
<email>paul@pierre.com</email>
<css>css/lite.css</css>
+ <!-- L'ordre des conversations est le même que lors de la sauvegarde du profile -->
+ <!-- Comprend également la conversation principal, dans ce cas la racine est à 0 -->
+ <conversation>
+ <racine>4</racine>
+ <page>1</page>
+ </conversation>
+ <!-- [..] -->
<information>blabla</information>
</reponse>
<pseudo>Paul</pseudo>
<email>paul@pierre.com</email>
<css>css/dark.css</css>
+ <conversation>
+ <racine>4</racine>
+ <page>1</page>
+ </conversation>
+ <!-- [..] -->
</action>
s -> c
<reponse name="profile">
<statut>ok|pas ok</statut>
- <information>balbla></information>
+ <information>balbla</information>
</reponse>
---------------------
Si dernierMessageId est absent alors le client ne possède pas de message.
-Page peut être omis, il a alors la valeur 1 (première page)
-dernierMessageId est en base 36 (l'histoire de rigoler un peu)
+Page peut être omis, il a alors la valeur 1 (première page).
+dernierMessageId est en base 36 (l'histoire de rigoler un peu).
+Les conversations données sont définies dans le profile.
c -> s
<action name="refreshMessages">
<cookie>LKJDLAKSJBFLKASN</cookie>
<nombreMessage>10</nombreMessage>
<dernierMessageId>6ZR</dernierMessageId>
- <page>1</page> <!-- page principale -->
- <conversation> <!-- la num 0 est considérée comme la conversation principale -->
- <racine>RE</racine>
- <page>1</page>
- </converation>
<!-- [..] -->
</action>
Euphorik - doc technique
-== Page message ==
-Classes :
+
+== euphorik.js ==
+Sequences :
+ * Chargement d'une page
+
+== pageMinichat.js ==
+=== Classes ===
* Messages
* Conversation
* Message
-Sequences :
+=== Séquences ===
* Attente de nouveaux messages
a) Messages.rafraichirMessages
b) pour chaque conversation
* Ajout d'un message
PageMinichat.envoyerMessage(pseudo, message) : requête AJAX
- * Création d'une conversation
- * Suppression d'une conversation
\ No newline at end of file
+ * Extraction d'une conversation
+ a) Conversation.click
+ b) Messages.ExtraireConversation(numMess)
+ c) User.ajouterConversation(numMess)
+ d) Messages.rafraichirMessages(true)
+
+ * Suppression d'une conversation
+
+=== Exemple de conversation ===
+Utilisé lors des tests
+
+m1
+m2 -> m1
+m3 -> m1
+m4 -> m2
+m5 -> m3
+m6 -> m3
+m7
+
+
+
+
+
this.login = ""\r
this.password = ""\r
this.email = ""\r
- this.css = jQuery("link#cssPrincipale").attr("href")\r
+ this.css = jQuery("link#cssPrincipale").attr("href")
+
+ // les conversations, une conversation est un objet possédant les attributs suivants :
+ // - racine (entier)
+ // - page (entier)
+ this.conversations = new Array()\r
}
Client.prototype.setCss = function(css)
this.css = css
jQuery("link#cssPrincipale").attr("href", this.css)
this.majMenu()
-
- /* enregistement automatique..
- if (!this.identifie())
- if (!this.enregistrement())
- return
- */
+
if (this.identifie())
this.flush()
+}
+
+/**
+ * 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
+ */
+Client.prototype.ajouterConversation = function(racine)
+{
+ this.conversations.push({racine : racine, page : 1})
+ this.flush()
}\r
Client.prototype.getXMLlogin = function(login, password)
nodeCSS.appendChild(XMLDocument.createTextNode(this.css))
XMLDocument.documentElement.appendChild(nodeCSS)
+ // mémorise les conversations affichées
+ if (this.conversations.length > 0)
+ {
+ var nodeConversations = XMLDocument.createElement("conversations")
+ XMLDocument.documentElement.appendChild(nodeConversations)
+ for (var i = 0; i < this.conversations.length; i++)
+ {
+ var nodeConv = XMLDocument.createElement("conversation")
+ nodeConversations.appendChild(nodeConv)
+
+ var nodeRacine = XMLDocument.createElement("racine")
+ nodeRacine.appendChild(XMLDocument.createTextNode(this.conversations[i].racine))
+ nodeConv.appendChild(nodeRacine)
+
+ var nodePage = XMLDocument.createElement("page")
+ nodePage.appendChild(XMLDocument.createTextNode(this.conversations[i].page))
+ nodeConv.appendChild(nodePage)
+ }
+ }
+
return XMLDocument
}
Client.prototype.flush = function()
{
thisClient = this
- //thisClient.util.log(this.util.xmlVersAction(this.getXMLProfile()).action)
+ //thisClient.util.log(this.util.xmlVersAction(this.getXMLProfile()).action)
jQuery.ajax(
{
async: true,
this.regexMessageTagMatch = /\{.*?\}>/g
this.regexMessageTagReplace = /^(.*?\{.*?\}>)*/
-
- this.messages = new Messages(this.client, this.formateur, this.util)
}
PageMinichat.prototype.contenu = function()
{
+// <input class="captcha" name="captcha" type="text" size="12"></input>\
return '\
<div id="smiles"></div>\
<form method="post" action="">\
- <p>\\r
- <input class="captcha" name="captcha" type="text" size="12"></input>\
+ <p>\
+ <input class="captcha" name="captcha" type="text" size="8" maxlength="8"></input>\
<input class="pseudo" name="pseudo" type="text" size="12" maxlength="50" value="<nick>"></input>\
<input class="message" name="message" type="text" size="80" maxlength="500" value=""></input>\
<button class="return"></button>\
jQuery("form input.pseudo").val(this.client.pseudo)
- this.messages.rafraichirMessages(true)\r
+ // cet appel ne doit pas être fait avant l'appel à 'charger'
+ this.messages = new Messages(this.client, this.formateur, this.util)
+
+ this.messages.rafraichirMessages(true)
\r
this.util.setCaretToEnd(jQuery("form input.message")[0])
}
/**
- * @return les id des messages qui ont été mis en evidence sous la forme d'un objet
+ * Renvoie les messages faisant partie d'une conversation.
+ * @param messages l'ensemble des messages de la conversation
+ * @return les id des messages qui ont été mis en evidence sous la forme d'un hash (object) {id => bool}
*/
-Message.prototype.afficherConversation = function(messages)
+Message.prototype.getConversation = function(messages)
{
// les messages faisant partie de la conversation
var messagesEnEvidence = {}
* @param numConv le numéro (appelé id) de la conversation
* @param formateur outil permettant la mise en forme du texte des messages
*/
-function Conversation(numConv, formateur)
+function Conversation(numConv, formateur, util)
{
var thisConversation = this
this.id = numConv
this.messageOver = null // le message sur lequel se trouve le curseur
this.formateur = formateur
+ this.util = util
this.messages = new Array()
this.messagesParId = new Object()
- this.idDernierMesssage = null // la racine de la conversation (string), null = conversation principale
+ this.idDernierMesssage = null
this.page = 1 // par défaut on se trouve sur la première page
-
+
jQuery("#conversations").append(
- "<div id = \"" + this.getId() + "\" />"
+ "<div id=\"" + this.getId() + "\" class=\"conversation\"></div>"
)
// enlève la mise en évidence pour la conversation
- jQuery(this.getId()).hover(
+ jQuery("#conversations #" + this.getId()).hover(
function(){},
function(event)
{
}
/**
- * Retourne l'id de la conversation sous la forme (par exemple) "#conv453"
+ * Retourne l'id de la conversation sous la forme (par exemple) "conv3".
*/
Conversation.prototype.getId = function()
{
- return "#" + this.id
+ return "conv" + this.id
}
Conversation.prototype.ajouterMessage = function(message)
Conversation.prototype.viderMessages = function()
{
this.messages = new Array()
- jQuery("#conversations " + this.getId()).empty()
+ jQuery("#conversations #" + this.getId()).empty()
}
/**
* Après l'ajout d'un ou plusieurs message cette méthode est appelée afin
* d'afficher les messages non-affichés.
+ * @param funClickExtract fonction (fun(numMess)) appellée lors du clic sur un bouton "extraire"
*/
-Conversation.prototype.flush = function()
+Conversation.prototype.flush = function(funClickExtract)
{
var thisConversation = this
- var idDernierMessageAffiche = jQuery("#conversations " + this.getId() + " div:first").attr("id")
+ var idDernierMessageAffiche = jQuery("#conversations #" + this.getId() + " div:first").attr("id")
if (idDernierMessageAffiche == undefined) idDernierMessageAffiche = "0"
var XHTML = ""
"<div id=\"" + message.id + "\" class=\"" + (parseInt(message.id, 36) % 2 == 0 ? "messagePair" : "messageImpair") + " message" +
(this.messages[i].appartientAuClient ? " proprietaire" : "") + (this.messages[i].clientARepondu ? " repondu" : "") + (this.messages[i].estUneReponse ? " reponse" : "") + (this.messages[i].systeme ? " systeme" : "") +
"\" >" +
+ "<div class=\"extraire\">></div>" +
"[<div class=\"date\">" + message.date + "</div>]" +
"<div class=\"pseudo\">" + this.formateur.traitementComplet(message.pseudo) + "</div>:" +
XHTMLrepondA +
- "<div class=\"contenu\">" + (message.systeme ? this.formateur.remplacerBalisesHTML(message.contenu) : this.formateur.traitementComplet(message.contenu, message.pseudo))+ "</div>" +
+ "<div class=\"contenu\">" + (message.systeme ? this.formateur.remplacerBalisesHTML(message.contenu) : this.formateur.traitementComplet(message.contenu, message.pseudo)) + "</div>" +
"</div>"
}
- jQuery("#conversations " + this.getId()).prepend(XHTML)
+ //alert(this.getId())
+ jQuery("#conversations #" + this.getId()).prepend(XHTML)
+ //alert(jQuery("#conversations").text())
+ // mise à jour des images (LightBox) après l'ajout de message
if (myLightbox != null)
myLightbox.updateImageList()
- var nbMessagesAffiche = jQuery("#conversations " + this.getId() + " .message").size()
+ var nbMessagesAffiche = jQuery("#conversations #" + this.getId() + " .message").size()
if (nbMessagesAffiche > this.nbMessageMax)
- jQuery("#conversations " + this.getId() + " .message").slice(this.nbMessageMax, nbMessagesAffiche).empty();
+ jQuery("#conversations #" + this.getId() + " .message").slice(this.nbMessageMax, nbMessagesAffiche).empty();
- jQuery("#conversations " + this.getId() + " .message").filter(function(){return parseInt(jQuery(this).attr("id"), 36) > parseInt(idDernierMessageAffiche, 36)}).each(
+ // Ajoute les événements liés à chaque message
+ jQuery("#conversations #" + this.getId() + " .message").filter(function(){return parseInt(jQuery(this).attr("id"), 36) > parseInt(idDernierMessageAffiche, 36)}).each(
function()
{
+ /*jQuery(".extraire", this).click(
+ function(event)
+ {
+ funClickExtract()
+ return false
+ }
+ )*/
jQuery(this).click(
function(event)
{
if (jQuery(event.target).is("a")) return
+
+ // l'id du message
+ idMess = jQuery(this).attr("id")
+
+ // extraction d'une conversation
+ if (jQuery(event.target).is(".extraire"))
+ {
+ funClickExtract(idMess)
+ return
+ }
var valCourant = jQuery("input.message").val()
if (valCourant == undefined) valCourant = ""
- var tag = jQuery(".pseudo", this).text() + "{" + jQuery(this).attr("id") + "}" + ">"
+ var tag = jQuery(".pseudo", this).text() + "{" + idMess + "}" + ">"
if (valCourant.indexOf(tag, 0) == -1)
jQuery("input.message").val(tag + " " + valCourant)
thisConversation.util.setCaretToEnd(jQuery("form input.message")[0])
var message = this.messagesParId[id]
if (message == undefined) return
- mess = message.afficherConversation(this)
+ mess = message.getConversation(this)
// FIXME : cet appel est très lent
- jQuery("#conversations " + this.getId() + " .message").each(
+ jQuery("#conversations #" + this.getId() + " .message").each(
function()
{
var jq = jQuery(this)
this.util = util
this.conversations = new Array() // les conversations, la première représente la conversation principale
- this.conversations[0] = new Conversation(0, this.formateur)
+ this.conversations[0] = new Conversation(0, this.formateur, this.util)
this.idDernierMesssage = null // l'id du dernier message connu
XMLDocument.documentElement.appendChild(nodePage)
// les conversations
- for (var i = 1; i < this.conversations.length; i++)
+ for (var i = 0; i < this.client.conversations.length; i++)
{
var nodeConversation = XMLDocument.createElement("conversation")
XMLDocument.documentElement.appendChild(nodeConversation)
var nodeRacine = XMLDocument.createElement("racine")
- nodeRacine.appendChild(XMLDocument.createTextNode(this.conversation.racine))
+ nodeRacine.appendChild(XMLDocument.createTextNode(this.client.conversations[i].racine))
nodeConversation.appendChild(nodeRacine)
var nodePageConv = XMLDocument.createElement("page")
- nodePageConv.appendChild(XMLDocument.createTextNode(this.conversation.page))
+ nodePageConv.appendChild(XMLDocument.createTextNode(this.client.conversations[i].page))
nodeConversation.appendChild(nodePageConv)
}
if (this.conversations[numConversation] == null)
this.conversations[numConversation] = new Conversation(numConversation, this.formateur)
+
this.conversations[numConversation].ajouterMessage(message)
}
*/
Messages.prototype.flush = function(numConv)
{
- this.conversations[numConv].flush()
+ var thisMessages = this
+
+ this.conversations[numConv].flush
+ (
+ // fonction appellée lors de la demande d'extraction d'une conversation
+ function(idMess)
+ {
+ thisMessages.client.ajouterConversation(idMess)
+ thisMessages.rafraichirMessages(true)
+ }
+ )
}
Messages.prototype.viderMessages = function()
end,
record_info(fields, user),
user
- ).
-
+ ).
% exemple de peuplage de la BD, utilisé pour les tests
peupler() ->
Pseudo = case xmerl_xpath:string("pseudo", Action) of [#xmlElement{content = [#xmlText{value = P2}]}] -> P2; _ -> Login end,
Email = case xmerl_xpath:string("email", Action) of [#xmlElement{content = [#xmlText{value = E}]}] -> E; _ -> undefined end,
Css = case xmerl_xpath:string("css", Action) of [#xmlElement{content = [#xmlText{value = C}]}] -> C; _ -> undefined end,
+ Conversations = case xmerl_xpath:string("conversations", Action) of
+ Conversations ->
+ % extraction de chaque conversation
+
+ _ -> []
+ end,
case euphorik_minichat:set_profile(Cookie, Login, Password, Pseudo, Email, Css) of
ok ->
xml_reponse_profile_ok();\r
date_derniere_connexion, % erlang:now(), est mis à jour lors de n'importe quelle activitée (envoie de message par exemple)\r
css = [], % string()
indice_flood = 0, % integer() est incrémenté lorsque l'utilisateur envoie trop rapidement des messages.
- conversations = [] % [integer()], la liste des messages correspondant au conversation\r
+ conversations = [] % [{integer(), integer()}], la liste des messages correspondant au conversation ainsi que la page affichée\r
}).
\ No newline at end of file
-buffer.1.path=../doc/TODO.txt\r
-buffer.1.position=1\r
-buffer.1.current=1\r
-\r
-buffer.2.path=../doc/protocole2.txt\r
-buffer.2.position=1\r
+# SciTE session file
+buffer.1.path=/home/gburri/projets/euphorik/doc/protocole2.txt
+buffer.1.position=1
+
+buffer.2.path=/home/gburri/projets/euphorik/doc/technique.txt
+buffer.2.position=1
+
+buffer.3.path=/home/gburri/projets/euphorik/doc/TODO.txt
+buffer.3.position=1
+buffer.3.current=1
-buffer.1.path=../modules/include/euphorik_defines.hrl
+# SciTE session file
+
+buffer.1.path=/home/gburri/projets/euphorik/modules/erl/euphorik_bd.erl
buffer.1.position=1
-buffer.2.path=../modules/include/euphorik_bd.hrl
+buffer.2.path=/home/gburri/projets/euphorik/modules/erl/euphorik_minichat.erl
buffer.2.position=1
-buffer.3.path=../modules/erl/euphorik_bd.erl
+buffer.3.path=/home/gburri/projets/euphorik/modules/erl/euphorik_minichat_conversation.erl
buffer.3.position=1
-buffer.4.path=../modules/erl/euphorik_minichat.erl
+buffer.4.path=/home/gburri/projets/euphorik/modules/erl/euphorik_protocole.erl
buffer.4.position=1
-buffer.5.path=../modules/erl/euphorik_minichat_conversation.erl
+buffer.5.path=/home/gburri/projets/euphorik/modules/erl/euphorik_requests.erl
buffer.5.position=1
-buffer.5.current=1
-buffer.6.path=../modules/erl/euphorik_protocole.erl
+buffer.6.path=/home/gburri/projets/euphorik/modules/include/euphorik_bd.hrl
buffer.6.position=1
-buffer.7.path=../modules/erl/euphorik_requests.erl
+buffer.7.path=/home/gburri/projets/euphorik/modules/include/euphorik_defines.hrl
buffer.7.position=1
+buffer.7.current=1
-buffer.1.path=../js/euphorik.js\r
-buffer.1.position=1\r
+# SciTE session file
-buffer.2.path=../js/pageMinichat.js\r
-buffer.2.position=1\r
-buffer.2.current=1\r
+buffer.1.path=/home/gburri/projets/euphorik/js/euphorik.js
+buffer.1.position=7787
-buffer.3.path=../js/pageProfile.js\r
-buffer.3.position=1\r
+buffer.2.path=/home/gburri/projets/euphorik/js/pageMinichat.js
+buffer.2.position=1044
+buffer.2.current=1
-buffer.4.path=../js/pageRegister.js\r
+buffer.3.path=/home/gburri/projets/euphorik/js/pageProfile.js
+buffer.3.position=1
+
+buffer.4.path=/home/gburri/projets/euphorik/js/pageRegister.js
buffer.4.position=1
+
+buffer.5.path=/home/gburri/projets/euphorik/css/1/euphorik.css
+buffer.5.position=1
+
+buffer.6.path=/home/gburri/projets/euphorik/css/1/pageMinichat.css
+buffer.6.position=1
+
+buffer.7.path=/home/gburri/projets/euphorik/css/1/pageProfileRegister.css
+buffer.7.position=1