www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 5842d02c611ff4f0c73fee467be6b4f00a965cb1
parent 70eec38a55c315cab872aada669ba24d445811cd
Author: Georges Dupéron <jahvascriptmaniac+github@free.fr>
Date:   Tue, 17 May 2011 20:44:56 +0200

Avancement partiel.

Diffstat:
Mcode/serveur/dump2sqlite.sh | 2+-
Mcode/serveur/php/jeu.php | 42+++++++++++++++---------------------------
Mcode/serveur/php/ressources/backend.inc | 86+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mcode/serveur/php/ressources/my-extensions.js | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mcode/serveur/php/ressources/pticlic.js | 441++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mcode/serveur/php/server.php | 2+-
6 files changed, 396 insertions(+), 242 deletions(-)

diff --git a/code/serveur/dump2sqlite.sh b/code/serveur/dump2sqlite.sh @@ -29,7 +29,7 @@ create table type_relation(name, num, extended_name, info); create table user(login primary key, mail, hash_passwd, score, ugroup); create table game(gid integer primary key autoincrement, eid_central_word, relation_1, relation_2, difficulty, author); create table game_cloud(gid, num, difficulty, eid_word, totalWeight, probaR1, probaR2, probaR0, probaTrash); -create table played_game(pgid integer primary key autoincrement, gid, login, timestamp); +create table played_game(pgid integer primary key autoincrement, gid, nonce, login, timestamp); create table played_game_cloud(pgid, gid, type, num, relation, weight, score); create table colon_nodes(eid); create table random_cloud_node(eid,nbneighbors); diff --git a/code/serveur/php/jeu.php b/code/serveur/php/jeu.php @@ -27,18 +27,15 @@ border: medium solid #4a4; background-color:#f0f8d0; border-radius:0.4em; } .relationBox { border-width: 3px; border-style: solid; border-radius:1em; padding: 0.5em; width: 95%; margin: 0 auto; } - .relationBox table { border-collapse: collapse; } - .relationBox img { display:block; } - .relationBox td { padding:0; } .formElement { width:30%; height: 10%; position:absolute; } .fitFont, .subFitFont { overflow:auto; } #score { text-align:center; } .marginBox { width: 90%; height: 90%; top: 5%; left:5%; position:absolute; } - #message { left:5%; top:5%; width:90%; height:10%; position:absolute; border-radius:1em; text-align:center; opacity:0.9; } + #message { left:25%; top:5%; width:50%; height:15%; position:absolute; border-radius:0.5em; text-align:center; opacity:0.9; } - html, body, #splash, #nojs { background-color:black; color: white; } + #splash, #nojs { background-color:black; color: white; } /* couleurs green */ - .screen { background-color:#ffffe0; color: black; } + body, .screen { background-color:#ffffe0; color: black; } #message { background-color:#f0f8d0; color:black; border:medium solid #4a4; } #mc-caption { color:#8b4; } #mn-caption-box { background-color:#f0f8d0; } @@ -49,7 +46,7 @@ .hot { background-color:yellow; } /* couleurs black */ - .black .screen { background-color:black; color: white; } + body.black, .black .screen { background-color:black; color: white; } .black #message { background-color:#222; color:white; border:medium solid #ccc; } .black #mc-caption { color:white; } .black #mn-caption-box { background-color:#222; } @@ -61,7 +58,7 @@ </style> </head> <body> - <div id="splash" class="screen" style="display:block"> + <div id="splash" class="screen"> <img src="ressources/img/splash.png" class="center" style="width:320px; height: 480px;"/> </div> <div id="game" class="screen"> @@ -93,12 +90,12 @@ <div class="icon-container"><img class="iconFitParent" alt="" src="ressources/img/72/default.png" /></div> <div class="icon-label subFitFont"><span class="text center">Configuration</span></div> </a> - <a href="#connect" style="right:55%; top:66%;"> + <a href="#connection" style="right:55%; top:66%;"> <div class="highlight"></div> <div class="icon-container"><img class="iconFitParent" alt="" src="ressources/img/72/default.png" /></div> <div class="icon-label subFitFont"><span class="text center">Connexion</span></div> </a> - <a hred="#info" style="left:55%; top:66%;"> + <a href="#info" style="left:55%; top:66%;"> <div class="highlight"></div> <div class="icon-container"><img class="iconFitParent" alt="" src="ressources/img/72/default.png" /></div> <div class="icon-label subFitFont"><span class="text center">À propos</span></div> @@ -117,14 +114,14 @@ <div class="marginBox fitFont"> <p> PtiClic a été conçu et développé par Mathieu Lafourcade - (LIRMM - Université Montpellier 2) et Virginie Zampa - (LIDILEM - Université Stendhal Grenoble 3) + (LIRMM - Université Montpellier 2) et Virginie Zampa + (LIDILEM - Université Stendhal Grenoble 3) </p> <p> La présente version pour SmartPhone sous Android, en cours de développement a été conçue et réalisée par des - étudiants en Master 1 à l'Université Montpellier II : - Yoann BONAVERO, Bertrand BRUN, John CHARRON et + étudiants en Master 1 à l'Université Montpellier 2 : + Yoann BONAVERO, Bertrand BRUN, John CHARRON et Georges DUPÉRON. </p> <p> @@ -170,17 +167,9 @@ </form> </div> <div id="templates" style="display: none;"> - <div class="relationBox"> - <table style="width:100%; position:relative;"> - <tr> - <td> - <img class="icon" alt="" src="ressources/img/72/default.png" style="width:72px; height:72px;" /> - </td> - <td> - <div class="text subFitFont"></div> - </td> - </tr> - </table> + <div class="relationBox subFitFont"> + <img class="icon" alt="" src="ressources/img/72/default.png" style="width:72px; height:72px; display:inline-block; vertical-align:middle;" /> + <span class="text" style="vertical-align:middle;"></span> </div> <div class="scoreLine"> <span class="word"></span> (<span class="score"></span>) @@ -188,4 +177,4 @@ </div> <div id="message" class="fitFont"><span class="text center">PtiClic…</span></div> </body> -</html> -\ No newline at end of file +</html> diff --git a/code/serveur/php/ressources/backend.inc b/code/serveur/php/ressources/backend.inc @@ -15,8 +15,8 @@ require_once("ressources/db.inc"); * randomGameCore(); * randomGame(); * formatWord($word); -* game2json($user, $gameId); -* game2array($user, $gameId); +* game2json($user, $gameId, $pgidNonce = "-1", $doPlayedGame = true); +* game2array($user, $gameId, $pgidNonce = "-1", $doPlayedGame = true); * createGame($nbParties, $mode); * createGameCore($cloudSize); * getGame($user, $nbGames, $mode); @@ -267,17 +267,17 @@ function cgInsert($centerEid, $cloud, $r1, $r2, $totalDifficulty) $gid = $db->lastInsertRowID(); $t = time(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgid1 = $db->lastInsertRowID(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgid2 = $db->lastInsertRowID(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgid0 = $db->lastInsertRowID(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgidT = $db->lastInsertRowID(); // TODO : R0 et Trash + corrections @@ -347,17 +347,17 @@ function insertCreatedGame($centerEid, $cloud, $r1, $r2, $totalDifficulty,$userN $gid = $db->lastInsertRowID(); $t = time(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgid1 = $db->lastInsertRowID(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgid2 = $db->lastInsertRowID(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgid0 = $db->lastInsertRowID(); - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) - VALUES (null, $gid, null, $t);"); + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) + VALUES (null, $gid, -1, null, $t);"); $pgidT = $db->lastInsertRowID(); // TODO : R0 et Trash + corrections @@ -441,27 +441,31 @@ function formatWord($word) { /** Formate une partie en JSON en l'imprimant. * @param user : l'utilisateur. * @param gameId : L'identifiant d'une partie. +* @param pgidNonce : pgid ou nonce de la partie. Peut être -1 uniquement si $doPlayedGame = true +* @param doPlayedGame : enregistrer un nouveau pgid ? */ -function game2json($user, $gameId) +function game2json($user, $gameId, $pgidNonce = "-1", $doPlayedGame = true) { global $stringRelations; $db = getDB(); - // TODO : factoriser avec game2array() . + // TODO : factoriser avec game2array(). // TODO : planter si la requête suivante échoue pour quelque raison que ce soit. - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) VALUES (null, ".$gameId.", '$user', -1);"); - $pgid = $db->lastInsertRowID(); + if ($doPlayedGame) { + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) VALUES (null, ".intval($gameId).", ".$pgidNonce.", '".SQLite3::escapeString($user)."', -1);"); + $pgidNonce = $db->lastInsertRowID(); + } // TODO Yoann : faire des tests d'erreur pour ces select ? $game = $db->query("select gid, (select name from node where eid = eid_central_word) as name_central_word, eid_central_word, relation_1, relation_2 from game where gid = ".$gameId.";"); $game = $game->fetchArray(); $retstr = ""; - $retstr .= '{"gid":'.$gameId.',"pgid":'.$pgid.',"relations":['; + $retstr .= '{"gid":'.$gameId.',"pgid":'.$pgidNonce.',"relations":['; $retstr .= '{"id":'.$game['relation_1'].', "name":'.json_encode(''.formatWord($stringRelations[$game['relation_1']])).'}'; $retstr .= ', {"id":'.$game['relation_2'].', "name":'.json_encode(''.formatWord($stringRelations[$game['relation_2']])).'}'; $retstr .= ', {"id":0, "name":'.json_encode(''.formatWord($stringRelations[0])).'}'; $retstr .= ', {"id":-1, "name":'.json_encode(''.formatWord($stringRelations[-1])).'}],'; - // $retstr .= '{"gid":'.$gameId.',"pgid":'.$pgid.',"cat1":'.$game['relation_1'].',"cat2":'.$game['relation_2'].',"cat3":0,"cat4":-1,'; + // $retstr .= '{"gid":'.$gameId.',"pgid":'.$pgidNonce.',"cat1":'.$game['relation_1'].',"cat2":'.$game['relation_2'].',"cat3":0,"cat4":-1,'; $retstr .= '"center":{"id":'.$game['eid_central_word'].',"name":'.json_encode(''.formatWord($game['name_central_word'])).'},'; $cloudsize = 0; @@ -486,16 +490,19 @@ function game2json($user, $gameId) } /** Récupère une partie sous forme de tableau. -* @param db : descripteur de la bdd (obtenu avec getDB()). * @param user : Login de l'utilisateur demandant la partie. * @param gameId : L'identifiant d'une partie. +* @param pgidNonce : pgid ou nonce de la partie. Peut être -1 uniquement si $doPlayedGame = true +* @param doPlayedGame : enregistrer un nouveau pgid ? */ -function game2array($user, $gameId) +function game2array($user, $gameId, $pgidNonce = "-1", $doPlayedGame = true) { $db = getDB(); // TODO : planter si la requête suivante échoue pour quelque raison que ce soit. - $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) VALUES (null, ".$gameId.", '$user', -1);"); - $pgid = $db->lastInsertRowID(); + if ($doPlayedGame) { + $db->exec("INSERT INTO played_game(pgid, gid, nonce, login, timestamp) VALUES (null, ".intval($gameId).", ".$pgidNonce.", '".SQLite3::escapeString($user)."', -1);"); + $pgidNonce = $db->lastInsertRowID(); + } // TODO Yoann : faire des tests d'erreur pour ces select ? $game = $db->query("select gid, (select name from node where eid = eid_central_word) as name_central_word, eid_central_word, relation_1, relation_2 from game where gid = ".$gameId.";"); @@ -503,7 +510,7 @@ function game2array($user, $gameId) $ret = array(); $ret['gid'] = $gameId; - $ret['pgid'] = $pgid; + $ret['pgid'] = $pgidNonce; $ret['cat1'] = $game['relation_1']; $ret['cat2'] = $game['relation_2']; $ret['cat3'] = 0; @@ -564,9 +571,22 @@ function createGameCore($cloudSize) * @param nbGames : Le nombre de parties à récupérer. * @param mode : Le mode de jeu des parties à récupérer. */ -function getGame($user) +function getGame($user, $pgidNonce = null) { - echo game2json($user, randomGame()); + $nonce = "-1"; + if ($pgidNonce !== null) { + if (substr($pgidNonce, 0, 1) == '-') { + $temp = getDB()->querySingle("SELECT gid,pgid FROM played_game WHERE nonce = ".preg_replace('/[^0-9]/', '', $pgidNonce)." and login = '".SQLite3::escapeString($user)."';", true); + $gid = $temp['gid']; + $nonce = $temp['pgid']; + if ($gid == null) { $nonce = preg_replace('/[^0-9]/', '', $pgidNonce); $pgidNonce = null; } + } else { + $nonce = intval($pgidNonce); + $gid = getDB()->querySingle("SELECT gid FROM played_game WHERE pgid = ".$pgidNonce." and login = '".SQLite3::escapeString($user)."';"); + if ($gid == null) throw new Exception("Cette partie n'est associée à votre nom d'utilisateur.", 4); + } + } + echo game2json($user, $pgidNonce == null ? randomGame() : $gid, $nonce, $pgidNonce == null); } @@ -618,11 +638,11 @@ function normalizeProbas($row) { function setGame($user, $pgid, $gid, $answers) { $db = getDB(); - if ('ok' !== $db->querySingle("SELECT 'ok' FROM played_game WHERE pgid = $pgid and $gid = $gid and login = '$user' and timestamp = -1;")) { + if ('ok' !== $db->querySingle("SELECT 'ok' FROM played_game WHERE pgid = $pgid and gid = $gid and login = '".SQLite3::escapeString($user)."' and timestamp = -1;")) { return getGameScores($user, $pgid, $gid); } - $userReputation = computeUserReputation($db->querySingle("SELECT score FROM user WHERE login='".SQLite3::escapeString($user)."';")); + $userReputation = computeUserReputation($db->querySingle("SELECT score FROM user WHERE login = '".SQLite3::escapeString($user)."';")); $db->exec("begin transaction;"); $db->exec("update played_game set timestamp = ".time()." where pgid = $pgid;"); diff --git a/code/serveur/php/ressources/my-extensions.js b/code/serveur/php/ressources/my-extensions.js @@ -8,10 +8,10 @@ Number.prototype.mapInterval = function(a,b,x,y) { return x + ((this-a) / (b-a) * (y-x)); } -function dichotomy(start, isBigger) { +dichotomyStop = false; +function dichotomy(start, isBigger, debug) { try { var i = 0, min = 0, max, half; - for (max = start || 1; ++i < 10 && !isBigger(max); max *= 2); for (half = start; Math.abs(min-max) > 0.1; half = (min + max) / 2) { if (!isBigger(half)) min = half; @@ -19,7 +19,7 @@ function dichotomy(start, isBigger) { } while (half > 1 && isBigger(half)) { --half; } return half; - } catch(e) {alert("Error dichotomy");alert(e);} + } catch(e) {alert("Error dichotomy");alert(e);throw(e);} } $.fn.fold = function(acc, fn) { @@ -43,13 +43,14 @@ $.fn.fitFont = function() { try { var that = this; var setFont = this.find('.setFont').andSelf(); + this.find('.center').css({top:0, left:0}); // Petit hack pour que ça ne déborde pas à cause de l'offset mis par .center(). var size = dichotomy(parseInt(this.css("font-size"), 10), function(x) { setFont.css("fontSize", x); return that.$ormap(function(i,e) { return e.hasScroll(); }); - }); + }, this); this.css("font-size", Math.max(0, size)); return this; - } catch(e) {alert("Error $.fn.fitFont");alert(e);} + } catch(e) {alert("Error $.fn.fitFont");alert(e);throw(e);} }; $.fn.swapCSS = function(k,v) { @@ -86,6 +87,7 @@ $.fn.qRemoveClass = queueize("removeClass"); $.fn.qShow = queueize("show"); $.fn.qHide = queueize("hide"); $.fn.qCss = queueize("css"); +$.fn.qText = queueize("text"); $.fn.wh = function(w, h) { try { @@ -159,8 +161,59 @@ var PtiClic = $({}); PtiClic.queueJSON = function(url, data, ok, error) { }; +function decodeHash(hash) { + /* hash.match(/^#([a-z]+(\/[0-9]+(\/-?[0-9]+(,-?[0-9]+)*)?)?)?$/) */ + hash = hash.substring(1).split('/'); + return { + screen:hash[0] || 'splash', + pgid:hash[1] || -1, + answers:(hash[2] ? hash[2].split(',') : []) + }; +} + +function encodeHash(data) { + var hash = "#"; + if (data.screen == '') return hash; + hash += data.screen + if (data.pgid == -1) return hash; + hash += '/'+data.pgid; + if (data.answers.length == 0) return hash; + hash += '/'+data.answers.join(','); + return hash; +} + +function Cache(resolver) { + var cache = []; + var self = this; + this.get = function(k) { + return cache[k] = cache[k] || $.Deferred(function(dfd) { resolver(k, dfd, self); }); + }; + this.alias = function(alias, k) { + cache[alias] = cache[alias] || $.Deferred(); + cache[k].done(function(data) { cache[alias].resolve(data); }); + }; +} + /* Enchaînement des écrans -Aller sur un écran donné. + +*** Utiliser un objet Deferred pour les fonctions qu'on ne veut apeller qu'une fois. + +*** + +- Cache des parties récupérées & scores (key = pgid pour les deux, mais params supplémentaires pour scores) +new Cache(queryFn(k, dfd, cache) { cache.set(k,v); dfd.resolve(data); }); +Cache.get(k) returns Promise; // Peut déclencher $.extend(Cache, queryFn(k)). + +- Récupérer une partie aléatoire, et la stocker dans le cache à son arrivée +- Afficher $(#game) (et $(#score)) une fois la partie (score) récupéré(e) et le(la) consommer +- Sauf si l'action a été annulée. +$.when(getGame, goGame) +if (runstate.nextScreen == 'game') … +- Lorsqu'une requête échoue, on demande le login, on retente la requête avec ce login/mdp. Si ça marche avec ce login/mdp, on .resolve(), sinon on .fail(). + +*** + +Aller sur un écran donné (parfois sans changer l'URL, par ex. pour splash→frontpage, et lorsqu'on force le login). Recevoir des données avant d'entrer dans un écran. Envoyer des données avant de quiter un écran. Vérouiller l'écran courant pendant qu'on attend un transfert ou bien des écrans d'«attente». diff --git a/code/serveur/php/ressources/pticlic.js b/code/serveur/php/ressources/pticlic.js @@ -1,13 +1,269 @@ // ==== URL persistante var nullFunction = function(){}; +var futureHashChange = null; +var runstate = { + screen: 'none', +}; +var state = decodeHash(""); +var oldstate = decodeHash(""); + +$.screen = function (name) { + return $(document.getElementById(name)).filter('.screen'); +} + +function hashchange() { + oldstate = state; + state = decodeHash(location.hash); + $.screen(state.screen).trigger(state.screen != runstate.screen ? "goto" : "update"); +} + +function init(fn) { + $(window).queue('init', function(next) {fn(); next();}); +} + +// ==== Code métier général +$(function() { + $(window).dequeue('init'); + $(window).resize(jss); + $(window).hashchange(hashchange); + hashchange(); + jss(); + runstate.loaded = true; +}); + +// ==== Nouveau jss +function jss() { + try { + if ($("#splash img").is(':visible')) { + var ratio = Math.min($('#splash').width() / 320, $('#splash').height() / 480); + $('#splash.screen img') + .wh(320 * ratio, 480 * ratio); + } + if ($('#game.screen').is(':visible')) { + var iconSize = 72; + var rel = $('#game.screen .relations'); + var rb = rel.find('.relationBox'); + rb.css({ + borderWidth: ({72:3,48:2,36:1})[iconSize], + padding: 10/72*iconSize, + borderRadius: 20/72*iconSize, + }).height(iconSize); + rb.css({ marginTop: (rel.height() - rb.sumOuterHeight()) / (rb.size() + 1) }); + rb.find('.icon').css({paddingRight: 10/72*iconSize}); + } + $('.iconFitParent').wh(0,0).each(function(i,e) { + e=$(e); + var p = e.parent(); + var size = Math.min(p.width(), p.height()); + if (size >= 72) { e.wh(72); } + else if (size >= 48) e.wh(48); + else if (size >= 36) e.wh(36); + else e.wh(0); + }); + $('.fitFont:visible').$each(function(i,e) { e.fitFont(); }); + $('.fitFontGroup:visible').each(function(i,e) { $(e).find('.subFitFont').fitFont(); }); + $('.center:visible').$each(function(i,e) { e.center(e.parent().center()); }); + } catch(e) {alert("Error jss");alert(e);} +} + +// ==== Passage d'un écran à l'autre + +init(function() { + $('.screen').live('goto', function() { + var screen = this.id; + if (screen == '') return; + // Afficher "Chargement…" + /* location.hash = "#" + screen; */ + $.screen(runstate.screen).trigger('leave').hide(); + runstate.screen = screen; + $(this).trigger('pre-enter'); + }); + + $('.screen').live('pre-enter', function() { + $(this).trigger('enter'); + }); + + $('.screen').live('enter', function() { + $(this).show(); + jss(); + }); + + $('.screen').live('leave', function() { + $(this).hide(); + }); +}); + +// ==== Bulle pour les messages +init(function() { + $('#message').hide(); +}); + +function message(title, msg) { + try { + $('#message') + .qCss('opacity',0).qShow() + .queue(function(next){ $('#message .text').text(msg); jss(); next(); }) + .fadeTo(700, 0.9).delay(5000).fadeOut(700); + } catch(e) {alert("Error UI().info");alert(e);} +} + +// ==== Écran splash +init(function() { + $('#splash.screen').click(function(){ $('#frontpage').trigger('goto'); }); + $('#splash.screen').bind('goto', function(e){ + if (runstate.loaded) { + $('#frontpage').trigger('goto'); + return false; + } + }); + +}); + +// ==== Écran game +runstate.gameCache = new Cache(function(k, dfd, cache) { + $.getJSON("getGame.php?callback=?", {pgid:k}, function(data) { + if (data.error == 10) { + $('#connection.screen').trigger('goto'); + } else if (data.isError) { + location.hash = "#frontpage"; + message("Erreur", "Une erreur est survenue, veuillez nous en excuser."); + } else { + cache.alias(data.pgid, k); + dfd.resolve(data); + } + }); +}); + +init(function() { + var game = $('#game.screen'); + $('a[href="#game"]').click(function() { + location.hash = '#game/-' + $.now(); + return false; + }); + + game.bind('pre-enter', function() { + runstate.gameCache.get(state.pgid).done(function(data) { + runstate.game = data + if (runstate.screen == 'game') { game.trigger('enter'); } + }); + return false; + }); -function State(init) { + game.bind('enter', function() { + $("#game .relations").empty(); + var game = runstate.game; + $.each(game.relations, function(i, relation) { + $('#templates .relationBox') + .clone() + .find(".text").html(relation.name.replace(/%(m[cn])/g, '<span class="$1"/>')).end() + .find(".icon").data("image",relation.id).end() + .click(function(e) { + state.pgid = game.pgid; + state.answers.push(relation.id); + location.hash = encodeHash(state); + $(this).addClass("hot").removeClass("hot", 1000); +/* try { + game.nextWord({left:e.pageX, top:e.pageY}, this); + } catch(e) {alert("Error anonymous 2 click in game.buildUi");alert(e);}*/ + }) + .appendTo("#game .relations"); + }); + $("#game .mn").text(game.cloud[state.answers.length].name); + $("#game .mc").text(game.center.name); + }); + + game.bind('update', function(e) { + $("#game .mn").text(runstate.game.cloud[state.answers.length].name); + jss(); + console.log('update'); + }); +}); + + +game = {}; +game.leave = function () { + try { + $("#game .relations").empty(); + $('#game #mn-caption').stop().clearQueue(); + if (runstate.gameFetched) runstate.gameFetched = nullFunction; + } catch(e) {alert("Error game.leave");alert(e);} +}; + +game.buildUi = function () { + try { + $("#game .relations").empty(); + $.each(state.game.relations, function(i, relation) { + try { + } catch(e) {alert("Error anonymous 1 in game.buildUi");alert(e);} + }); + game.updateText(); + } catch(e) {alert("Error game.buildUi");alert(e);} +} + +game.updateText = function() { + try { + $("#game .mn").text(state.game.cloud[state.currentWordNb].name); + $("#game .mc").text(state.game.center.name); + jss(); + UI().dismiss(); + } catch(e) {alert("Error game.updateText");alert(e);} +} + +game.animateNext = function (click, button) { + try { + var duration = 700; + + var mn = $("#game #mn-caption"); + + $(button).addClass("hot").removeClass("hot", duration); + + (mn) + .stop() // Attention : stop() et clearQueue() ont aussi un effet + .clearQueue() // sur la 2e utilisation de mn (ci-dessous). + .clone() + .removeClass("mn") // Pour que le texte animé ne soit pas modifié. + .appendTo("body") // Append to body so we can animate the offset (instead of top/left). + .offset(mn.offset()) + .animate({left:click.left, top:click.top, fontSize: 0}, duration) + .queue(function() { + try { + $(this).remove(); + } catch(e) {alert("Error anonymous 1 in game.animateNext");alert(e);} + }); + + game.updateText(); + var fs = mn.css("fontSize"); + var mncbCenter = $("#game #mn-caption-block").center(); + + (mn) + .css("fontSize", 0) + .animate({fontSize: fs}, {duration:duration, step:function(){ + try { + mn.center(mncbCenter); + } catch(e) {alert("Error anonymous 2 in game.animateNext");alert(e);} + }}); + } catch(e) {alert("Error game.animateNext");alert(e);} +} + +game.nextWord = function(click, button) { + try { + state.game.answers[state.currentWordNb++] = $(button).data("rid"); + if (state.currentWordNb < state.game.cloud.length) { + game.animateNext(click, button); + state.commit(); + } else { + state.set('screen','score').validate(); + } + } catch(e) {alert("Error game.nextWord");alert(e);} +} + + +/*function State(init) { try { $.extend(this, init || {}); if (!this.screen) this.screen = 'splash'; } catch(e) {alert("Error State");alert(e);} }; -var futureHashChange = null; State.prototype.commit = function() { try { futureHashChange = "#"+encodeURI('"'+$.JSON.encode(this)); @@ -37,21 +293,13 @@ State.prototype.validate = function () { if (window[this.screen] && window[this.screen].enter) window[this.screen].enter(); return this; } catch(e) {alert("Error State.prototype.validate");alert(e);} -}; +};*/ -var runstate = {}; -var state; -var oldScreen = ''; -var ui = {}; -function hashchange() { +function _hashchange() { try { - if (futureHashChange === location.hash) { - futureHashChange = null; - } else { - var stateJSON = location.hash.substring(location.hash.indexOf("#") + 1); - if (stateJSON.charAt(0) != '"') { stateJSON = decodeURI(stateJSON); } - stateJSON = stateJSON.substring(1); - state = new State($.parseJSON(stateJSON || '{}')).validate(); + if (futureHashChange !== location.hash) { + state = decodeHash(location.hash); + // Appliquer le changement de screen etc. } } catch(e) {alert("Error hashchange");alert(e);} } @@ -85,70 +333,6 @@ function UI () { } catch(e) {alert("Error UI");alert(e);} } -function UIInfo(title, msg) { - try { - $('#message') - .qCss('opacity',0) - .qShow() - .queue(function(next){ - try { - $('#message .text').text(msg); - jss(); - next(); - } catch(e) {alert("Error anonymous in UIInfo");alert(e);} - }) - .animate({opacity:0.9}, 700) - .delay(5000) - .animate({opacity:0}, 700); - } catch(e) {alert("Error UI().info");alert(e);} -} - -// ==== Nouveau jss -function jss() { - try { - if ($("#splash img").is(':visible')) { - var ratio = Math.min($('#splash').width() / 320, $('#splash').height() / 480); - $('#splash.screen img') - .wh(320 * ratio, 480 * ratio); - } - if ($('#game.screen').is(':visible')) { - var iconSize = 72; - var rel = $('#game.screen .relations'); - var rb = rel.find('.relationBox'); - $('.relationBox').css({ - borderWidth: ({72:3,48:2,36:1})[iconSize], - padding: 10/72*iconSize, - borderRadius: 20/72*iconSize, - marginTop: (rel.height() - rb.sumOuterHeight()) / (rb.size() + 1) - }); - $('.relationBox .icon').css({paddingRight: 10/72*iconSize}); - } - $('.iconFitParent').wh(0,0).each(function(i,e) { - e=$(e); - var p = e.parent(); - var size = Math.min(p.width(), p.height()); - if (size >= 72) { e.wh(72); } - else if (size >= 48) e.wh(48); - else if (size >= 36) e.wh(36); - else e.wh(0); - }); - $('.fitFont:visible').$each(function(i,e) { e.fitFont(); }); - $('.fitFontGroup:visible').each(function(i,e) { $(e).find('.subFitFont').fitFont(); }); - $('.center').$each(function(i,e) { e.center(e.parent().center()); }); - } catch(e) {alert("Error jss");alert(e);} -} - -// ==== Code métier général -$(function() { - try { - $(window).resize(jss); - $(window).hashchange(function(){alert("hashchange !");}); - //hashchange(); - jss(); - runstate.loaded = true; - } catch(e) {alert("Error main function");alert(e);} -}); - // ==== Asynchronous Javascript And Json. ajaj = {}; ajaj.request = function(url, data, okFunction, smallErrorFunction, bigErrorFunction) { @@ -306,97 +490,6 @@ game.enter = function () { } catch(e) {alert("Error game.enter");alert(e);} }; -game.leave = function () { - try { - $("#game .relations").empty(); - $('#game #mn-caption').stop().clearQueue(); - if (runstate.gameFetched) runstate.gameFetched = nullFunction; - } catch(e) {alert("Error game.leave");alert(e);} -}; - -game.buildUi = function () { - try { - $("#game .relations").empty(); - $.each(state.game.relations, function(i, relation) { - try { - $('#templates .relationBox') - .clone() - .data("rid", relation.id) - .find(".text") - .html(relation.name.replace(/%(m[cn])/g, '<span class="$1"/>')) - .end() - .find(".icon") - .data("image",relation.id) - .end() - .click(function(e) { - try { - game.nextWord({left:e.pageX, top:e.pageY}, this); - } catch(e) {alert("Error anonymous 2 click in game.buildUi");alert(e);} - }) - .appendTo("#game .relations"); - } catch(e) {alert("Error anonymous 1 in game.buildUi");alert(e);} - }); - game.updateText(); - } catch(e) {alert("Error game.buildUi");alert(e);} -} - -game.updateText = function() { - try { - $("#game .mn").text(state.game.cloud[state.currentWordNb].name); - $("#game .mc").text(state.game.center.name); - jss(); - UI().dismiss(); - } catch(e) {alert("Error game.updateText");alert(e);} -} - -game.animateNext = function (click, button) { - try { - var duration = 700; - - var mn = $("#game #mn-caption"); - - $(button).addClass("hot").removeClass("hot", duration); - - (mn) - .stop() // Attention : stop() et clearQueue() ont aussi un effet - .clearQueue() // sur la 2e utilisation de mn (ci-dessous). - .clone() - .removeClass("mn") // Pour que le texte animé ne soit pas modifié. - .appendTo("body") // Append to body so we can animate the offset (instead of top/left). - .offset(mn.offset()) - .animate({left:click.left, top:click.top, fontSize: 0}, duration) - .queue(function() { - try { - $(this).remove(); - } catch(e) {alert("Error anonymous 1 in game.animateNext");alert(e);} - }); - - game.updateText(); - var fs = mn.css("fontSize"); - var mncbCenter = $("#game #mn-caption-block").center(); - - (mn) - .css("fontSize", 0) - .animate({fontSize: fs}, {duration:duration, step:function(){ - try { - mn.center(mncbCenter); - } catch(e) {alert("Error anonymous 2 in game.animateNext");alert(e);} - }}); - } catch(e) {alert("Error game.animateNext");alert(e);} -} - -game.nextWord = function(click, button) { - try { - state.game.answers[state.currentWordNb++] = $(button).data("rid"); - if (state.currentWordNb < state.game.cloud.length) { - game.animateNext(click, button); - state.commit(); - } else { - state.set('screen','score').validate(); - } - } catch(e) {alert("Error game.nextWord");alert(e);} -} - // ==== Code métier pour les scores score = {}; @@ -526,10 +619,10 @@ connection.connectFetched = function(data) { try { if (data && data.theme) { prefs.loadPrefs(); - UIInfo("Connexion", "Vous êtes connecté !"); + message("Connexion", "Vous êtes connecté !"); } else if (data && data.isError && data.error == 3) { prefs.loadPrefs(); - UIInfo("Connexion", data.msg); + message("Connexion", data.msg); } else { prefs.loadPrefs(); ajaj.smallError(data); @@ -563,10 +656,10 @@ prefs.apply = function(){ }, function(data) { try { if (data.theme) { - UIInfo("Préférences", "Les préférences ont été enregistrées."); + message("Préférences", "Les préférences ont été enregistrées."); prefs.loadPrefs(data); } else { - UIInfo("Préférences", "Les préférences n'ont pas pu être enregistrées."); + message("Préférences", "Les préférences n'ont pas pu être enregistrées."); } } catch(e) {alert("Error anonymous in prefs.apply");alert(e);} }); diff --git a/code/serveur/php/server.php b/code/serveur/php/server.php @@ -75,7 +75,7 @@ function main() } else if($action == 0) { // "Get partie" // Requête POST : http://serveur/server.php?action=0&user=foo&passwd=bar - getGame($user); + getGame($user, isset($_GET['pgid']) ? $_GET['pgid'] : null); } else if($action == 1) { // "Set partie" // Requête POST : http://serveur/server.php?action=1&mode=normal&user=foo&passwd=bar&gid=1234&pgid=12357&0=0&1=-1&2=22&3=13&9=-1