From 8b0d78910cfc368456d81cd301b9999f96b0d5d7 Mon Sep 17 00:00:00 2001 From: Yoann Date: Wed, 23 Mar 2011 17:15:46 +0100 Subject: [PATCH 01/20] =?UTF-8?q?D=C3=A9but=20html5=20(=3F)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/html5/img/aide.png | Bin 0 -> 9310 bytes code/html5/img/config.png | Bin 0 -> 7874 bytes code/html5/img/icon.png | Bin 0 -> 7937 bytes code/html5/img/mode_chrono.png | Bin 0 -> 10208 bytes code/html5/img/mode_marathon.png | Bin 0 -> 7867 bytes code/html5/img/mode_normal.png | Bin 0 -> 6296 bytes code/html5/img/mode_ombre.png | Bin 0 -> 9239 bytes code/html5/img/rel/-1.png | Bin 0 -> 6767 bytes code/html5/img/rel/0.png | Bin 0 -> 8567 bytes code/html5/img/rel/10.png | Bin 0 -> 6124 bytes code/html5/img/rel/5.png | Bin 0 -> 7623 bytes code/html5/img/rel/7.png | Bin 0 -> 6004 bytes code/html5/img/rel/9.png | Bin 0 -> 7744 bytes code/html5/img/splash.png | Bin 0 -> 98035 bytes code/html5/index.html | 55 +++++++++++++++++++++++++++++++ 15 files changed, 55 insertions(+) create mode 100644 code/html5/img/aide.png create mode 100644 code/html5/img/config.png create mode 100644 code/html5/img/icon.png create mode 100644 code/html5/img/mode_chrono.png create mode 100644 code/html5/img/mode_marathon.png create mode 100644 code/html5/img/mode_normal.png create mode 100644 code/html5/img/mode_ombre.png create mode 100644 code/html5/img/rel/-1.png create mode 100644 code/html5/img/rel/0.png create mode 100644 code/html5/img/rel/10.png create mode 100644 code/html5/img/rel/5.png create mode 100644 code/html5/img/rel/7.png create mode 100644 code/html5/img/rel/9.png create mode 100644 code/html5/img/splash.png create mode 100644 code/html5/index.html diff --git a/code/html5/img/aide.png b/code/html5/img/aide.png new file mode 100644 index 0000000000000000000000000000000000000000..8027fbca2364170bbdc802ba599ed48610b9776c GIT binary patch literal 9310 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 M07*qoM6N<$f-x&QzG literal 0 HcmV?d00001 diff --git a/code/html5/img/config.png b/code/html5/img/config.png new file mode 100644 index 0000000000000000000000000000000000000000..7a1fb5ca5a0f6d267dd8212e5716bbc715fd5f33 GIT binary patch literal 7874 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

DE@j0!z8ZGN2`fw!sg-Ws_9VfU1PRL~J-wKv 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 literal 0 HcmV?d00001 diff --git a/code/html5/img/mode_chrono.png b/code/html5/img/mode_chrono.png new file mode 100644 index 0000000000000000000000000000000000000000..28e7d535f5b362e8ebc0ad5e13d227ff272fb937 GIT binary patch literal 10208 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 literal 0 HcmV?d00001 diff --git a/code/html5/img/mode_normal.png b/code/html5/img/mode_normal.png new file mode 100644 index 0000000000000000000000000000000000000000..104c573b6f8f7af0155f599e2be0990ee9fcfb91 GIT binary patch literal 6296 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

L zQAdj9bDp_Z4X>s)j^;;h7SP34)-bMK$M~o;Y0XaXG>kq~06fd7%ub^5l%l_VcsHf0 zQmbc?%tvs(>Uf+lz2P2@HRxE`FFv**#v>(6CFU(!aF!EoHJPZULMf4fqZzOC(dV*G zqFvMn1=9N{ebiF0j^qbsl~GG@1tmHTLs6=hF`zUwl}}k^A#Ghd1_Yz9_6|c>i$?27 z`h3lESSO`c3N=q+_?Z_yU;fS`x^DT=9}>?26Hxl>u(d7*^f9<=?Kq^V!B$63?BhIQYYby5R9C8NGFvlV&bZ9ez}9q~V{6i8GpodDE$!Hem=%e(x0E~vtj*8X z0db4@xa|9pJvc?b3Y^D1f$9lA{(~|0VnVI0x84rOs%dM=>=SVqQ3EIIh!oKr(pSW5 z9=jDqi>?GvQev_v#+-~I7RTwR(-)->>aoy}%*n7u8MS%0ad<8#g5tmp#E zHFd1BIBu}lFy>u`3k#z4T%tEdM`regs=-|zT=7n#F0I1gg+XDRUU6+v$6k90m6eXQ xC`Mths1#O@qqhbWFT!BLkKJ*n{Qnqh{}13+TZa8AcWD3s002ovPDHLkV1oTTjAj4; literal 0 HcmV?d00001 diff --git a/code/html5/img/rel/10.png b/code/html5/img/rel/10.png new file mode 100644 index 0000000000000000000000000000000000000000..c3c1c48ea840346b839c20cdc95215fe20e45f07 GIT binary patch literal 6124 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 literal 0 HcmV?d00001 diff --git a/code/html5/img/rel/7.png b/code/html5/img/rel/7.png new file mode 100644 index 0000000000000000000000000000000000000000..1f7e04ad42e19e4e00672fa4f99a5dfa4040b6f0 GIT binary patch literal 6004 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 + +

-
-
-
+
+
+
+
+
diff --git a/code/html5/jquery-ui-1.8.11.custom.min.js b/code/html5/jquery-ui-1.8.11.custom.min.js new file mode 100644 index 0000000..0251a19 --- /dev/null +++ b/code/html5/jquery-ui-1.8.11.custom.min.js @@ -0,0 +1,17 @@ +/* + * jQuery UI Position 1.8.11 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Position + */ +(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, +left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= +k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= +m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= +d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= +a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), +g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); +; \ No newline at end of file diff --git a/code/html5/my-extensions.js b/code/html5/my-extensions.js new file mode 100644 index 0000000..827f980 --- /dev/null +++ b/code/html5/my-extensions.js @@ -0,0 +1,35 @@ +$.fn.fitFont = function(w, h, minFont, maxFont) { + minFont = minFont || 0; + maxFont = maxFont || Infinity; + e = $(this) + var oldpos = e.css("position"); + e.css("position", "absolute"); + var size = parseInt(e.css("font-size"), 10); + + var i = 0; + while ((e.width() < w || e.height() < h) && ++i < 10) { + size *= 2; + e.css("font-size", size); + } + + var max = size; + var min = 0; + i=0; + while (min < max && ++i < 10) { + size = (max + min) / 2; + e.css("font-size", size); + if (e.width() < w && e.height() < h) { + min = size; + } else { + max = size; + } + } + + if (e.width() > w || e.height() > h) --size; + if (size < minFont) size = minFont; + if (size > maxFont) size = maxFont; + e.css("font-size", size); + + e.css("position", oldpos); + return e; +} diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index aa66523..a4dfe98 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -1,16 +1,36 @@ -$(function () { -/* window.setTimeout(function() { - var w=480; - var h=800; - var a=[]; $("#screen").find("*").add("#screen").each(function(i,e){ a.push({ - e:$(e), - w:$(e).width()*w/480, - h:$(e).height()*h/800}); - }); - $.each(a,function(i,a){ a.e.width(a.w); a.e.height(a.h); }); -}, 1000); */ +function jss() { + var w=480, h=800; + var mch = h/8, mnh = h*0.075; + $("#screen") + .width(w) + .height(h) - var url = "tmp.json" + $("#mc-caption-block") + .width(w) + .height(mch) + .position({my:"center top", at:"center top", of:"#screen", collision:"none"}); + $("#mc-caption") + .fitFont(w*0.9, mch*0.9, 20) + .css("max-width", w*0.9) + .position({my:"center center", at:"center center", of:"#mc-caption-block", collision:"none"}); + + $("#mn-caption-block") + .width(w) + .height(mnh) + .css("border-width", h/100) + .position({my:"center top", at:"center bottom", of:"#mc-caption-block", collision:"none"}); + $("#mn-caption") + .fitFont(w*0.9, mnh*0.9, 20) + .css("max-width", w*0.9) + .position({my:"center center", at:"center center", of:"#mn-caption-block", collision:"none"}); + + $("#screen") + .position({my:"center center", at:"center center", of:"body", collision:"none"}); +} + + +$(function () { + var url = "tmp.json"; $.getJSON(url, function(data) { var game = data[0]; var currentWordNb = 0; @@ -24,6 +44,7 @@ $(function () { $(".relations").empty(); alert("Partie terminée !"); } + jss(); } $.each(game.cat, function(i, cat) { From 8155b58d5c93ca0ffe12e5b4f2317f178aa90678 Mon Sep 17 00:00:00 2001 From: Bertrand BRUN Date: Mon, 4 Apr 2011 10:52:39 +0200 Subject: [PATCH 09/20] Modification de l'application pour qu'elle puisse utiliser la version html du jeux --- code/PtiClic/AndroidManifest.xml | 38 +- code/PtiClic/res/layout/basegame.xml | 104 ----- code/PtiClic/res/layout/frontpage.xml | 45 +- code/PtiClic/res/layout/score.xml | 76 --- code/PtiClic/src/org/pticlic/BaseScore.java | 149 ------ code/PtiClic/src/org/pticlic/FrontPage.java | 100 +--- code/PtiClic/src/org/pticlic/Information.java | 2 +- .../src/org/pticlic/games/BaseGame.java | 433 ------------------ .../src/org/pticlic/model/Constant.java | 2 +- .../org/pticlic/model/DownloadedBaseGame.java | 144 ------ .../src/org/pticlic/model/DownloadedGame.java | 57 --- code/PtiClic/src/org/pticlic/model/Match.java | 74 --- .../src/org/pticlic/model/Network.java | 183 -------- .../src/org/pticlic/model/Relation.java | 88 ---- 14 files changed, 37 insertions(+), 1458 deletions(-) delete mode 100644 code/PtiClic/res/layout/basegame.xml delete mode 100644 code/PtiClic/res/layout/score.xml delete mode 100644 code/PtiClic/src/org/pticlic/BaseScore.java delete mode 100644 code/PtiClic/src/org/pticlic/games/BaseGame.java delete mode 100644 code/PtiClic/src/org/pticlic/model/DownloadedBaseGame.java delete mode 100644 code/PtiClic/src/org/pticlic/model/DownloadedGame.java delete mode 100644 code/PtiClic/src/org/pticlic/model/Match.java delete mode 100644 code/PtiClic/src/org/pticlic/model/Relation.java diff --git a/code/PtiClic/AndroidManifest.xml b/code/PtiClic/AndroidManifest.xml index 33fc440..c1b936c 100644 --- a/code/PtiClic/AndroidManifest.xml +++ b/code/PtiClic/AndroidManifest.xml @@ -1,24 +1,28 @@ - - - - - - - + package="org.pticlic" android:versionCode="1" android:versionName="@string/version"> + + + + + + + - - - - - - + + + + + + + + - + - + diff --git a/code/PtiClic/res/layout/basegame.xml b/code/PtiClic/res/layout/basegame.xml deleted file mode 100644 index 9e5a90e..0000000 --- a/code/PtiClic/res/layout/basegame.xml +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/PtiClic/res/layout/frontpage.xml b/code/PtiClic/res/layout/frontpage.xml index fbcef16..3b80fb5 100644 --- a/code/PtiClic/res/layout/frontpage.xml +++ b/code/PtiClic/res/layout/frontpage.xml @@ -1,41 +1,6 @@ - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/code/PtiClic/res/layout/score.xml b/code/PtiClic/res/layout/score.xml deleted file mode 100644 index 312a0d8..0000000 --- a/code/PtiClic/res/layout/score.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/code/PtiClic/src/org/pticlic/BaseScore.java b/code/PtiClic/src/org/pticlic/BaseScore.java deleted file mode 100644 index 97ffbdf..0000000 --- a/code/PtiClic/src/org/pticlic/BaseScore.java +++ /dev/null @@ -1,149 +0,0 @@ -package org.pticlic; - -import org.pticlic.R.string; -import org.pticlic.exception.PtiClicException; -import org.pticlic.model.Constant; -import org.pticlic.model.DownloadedBaseGame; -import org.pticlic.model.Match; -import org.pticlic.model.Network; -import org.pticlic.model.Network.Mode; -import org.pticlic.model.Network.ScoreResponse; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.TextView; - -/** - * @author John CHARRON - * - * Permet l'affichage du score obtenu par le joueur lors de sa partie. - */ -public class BaseScore extends Activity implements OnClickListener{ - - private Match gamePlayed; - private ScoreResponse sr = null; - - private void networkStuff() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - String id = sp.getString(Constant.USER_ID, "joueur"); - String passwd = sp.getString(Constant.USER_PASSWD, ""); - String serverURL = sp.getString(Constant.SERVER_URL, Constant.SERVER); - Mode mode = null; - - if (getIntent().getExtras() != null) { - // GamePlayed contient toutes les infos sur la partie jouee - this.gamePlayed = (Match) getIntent().getExtras().get(Constant.SCORE_GAMEPLAYED); - mode = (Mode) getIntent().getExtras().get(Constant.SCORE_MODE); - } - - // TODO : factoriser le serverUrl dans Network - sp.edit().remove(Constant.NEW_BASE_GAME).commit(); - Network network = new Network(serverURL, mode, id, passwd); - try { - sr = network.sendBaseGame(gamePlayed); - sp.edit().putString(Constant.NEW_BASE_GAME, sr.getNewGame()).commit(); - } catch (PtiClicException e) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(e.getMessage()) - .setCancelable(false) - .setNegativeButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - finish(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } catch (Exception e) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(R.string.server_down) - .setCancelable(false) - .setNegativeButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - finish(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.score); - - this.networkStuff(); - this.networkStuff(); - - // TODO : Attention, le cast en (BaseGame) n'est pas sûr ! - DownloadedBaseGame bg = (DownloadedBaseGame)gamePlayed.getGame(); - ((TextView)findViewById(R.id.total)).setText(String.valueOf(sr.getScoreTotal())); - ((TextView)findViewById(R.id.scoreRel1)).setText(bg.getCatString(1)); - ((TextView)findViewById(R.id.scoreRel2)).setText(bg.getCatString(2)); - ((TextView)findViewById(R.id.scoreRel3)).setText(bg.getCatString(3)); - ((TextView)findViewById(R.id.scoreRel4)).setText(bg.getCatString(4)); - - String res; - String noAnswers = getString(string.score_no_answers); - res = ""; - for (int i : gamePlayed.getRelation1()) { - res += bg.getWordInCloud(i).getName(); - res += " (" + String.valueOf(sr.getScoreOfWord(i)) + "), "; - } - ((TextView)findViewById(R.id.scoreWords1)).setText(res.length() < 1 ? noAnswers : res); - - res = ""; - for (int i : gamePlayed.getRelation2()) { - res += bg.getWordInCloud(i).getName(); - res += " (" + String.valueOf(sr.getScoreOfWord(i)) + "), "; - } - ((TextView)findViewById(R.id.scoreWords2)).setText(res.length() < 1 ? noAnswers : res); - - res = ""; - for (int i : gamePlayed.getRelation3()) { - res += bg.getWordInCloud(i).getName(); - res += " (" + String.valueOf(sr.getScoreOfWord(i)) + "), "; - } - ((TextView)findViewById(R.id.scoreWords3)).setText(res.length() < 1 ? noAnswers : res); - - res = ""; - for (int i : gamePlayed.getRelation4()) { - res += bg.getWordInCloud(i).getName(); - res += " (" + String.valueOf(sr.getScoreOfWord(i)) + "), "; - } - ((TextView)findViewById(R.id.scoreWords4)).setText(res.length() < 1 ? noAnswers : res); - - ((Button)findViewById(R.id.saw)).setOnClickListener(this); - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - - finish(); - } - - protected double calculateTotal(){ - throw new UnsupportedOperationException(); - } - - @Override - public void onClick(View v) { - if (v.getId()==R.id.saw) { - finish(); - } - } -} diff --git a/code/PtiClic/src/org/pticlic/FrontPage.java b/code/PtiClic/src/org/pticlic/FrontPage.java index 42dd995..b397d51 100644 --- a/code/PtiClic/src/org/pticlic/FrontPage.java +++ b/code/PtiClic/src/org/pticlic/FrontPage.java @@ -1,25 +1,15 @@ package org.pticlic; -import org.pticlic.games.BaseGame; import org.pticlic.model.Constant; -import org.pticlic.model.Network; import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageView; -import android.widget.TextView; +import android.webkit.WebSettings; +import android.webkit.WebView; -public class FrontPage extends Activity implements OnClickListener{ +public class FrontPage extends Activity { - private Uri uri = null; + private WebView webView; /** Called when the activity is first created. */ @Override @@ -27,83 +17,11 @@ public class FrontPage extends Activity implements OnClickListener{ super.onCreate(savedInstanceState); setContentView(R.layout.frontpage); - // Écoute des clics sur les différents boutons - ((ImageView)findViewById(R.id.prefs)).setOnClickListener(this); - ((ImageView)findViewById(R.id.play)).setOnClickListener(this); - ((ImageView)findViewById(R.id.infoButton)).setOnClickListener(this); - - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - String serverURL = sp.getString(Constant.SERVER_URL, Constant.SERVER); - Uri.parse(serverURL + "/signup.php"); - } - - @Override - protected void onStart() { - super.onStart(); - - // On récupère le nom du joueur des préférences. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - Boolean connected = sp.getBoolean(Constant.SERVER_AUTH, false); - if (connected) { - ((TextView)findViewById(R.id.login)).setText(R.string.frontpage_user_connected); - } else { - ((TextView)findViewById(R.id.login)).setText(R.string.frontpage_user_notconnected); - } - } - - /* (non-Javadoc) - * @see android.view.View.OnClickListener#onClick(android.view.View) - */ - @Override - public void onClick(View v) { - switch (v.getId()) { - case (R.id.prefs) : startActivity(new Intent(this, Preference.class)); break; - case (R.id.play) : checkAllIsOk(BaseGame.class); break; - case (R.id.infoButton) : startActivity(new Intent(this, Information.class)); break; - } - } - - @SuppressWarnings("rawtypes") - private void checkAllIsOk(Class c) { - if (Network.isConnected(this)) { - if (Network.isLoginCorrect(this)) { - startActivity(new Intent(this, c)); - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(getString(R.string.frontpage_bad_loginmdp)) - .setCancelable(false) - .setNeutralButton(getString(R.string.frontpage_inscription_button), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - // TODO : Essayer de trouver comment mettre l'url qui est dans les preferences. - startActivity(new Intent(Intent.ACTION_VIEW, uri)); - } - }) - .setPositiveButton(getString(R.string.frontpage_preference_button), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.dismiss(); - startActivity(new Intent(getApplicationContext(), Preference.class)); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } - } else { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(getString(R.string.frontpage_no_connection)) - .setCancelable(false) - .setNegativeButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } + webView = (WebView) findViewById(R.id.webview); + WebSettings webSettings = webView.getSettings(); + webSettings.setJavaScriptEnabled(true); + + webView.loadUrl(Constant.SERVER + Constant.SERVER_URL); } @Override diff --git a/code/PtiClic/src/org/pticlic/Information.java b/code/PtiClic/src/org/pticlic/Information.java index d106f83..015ce2c 100644 --- a/code/PtiClic/src/org/pticlic/Information.java +++ b/code/PtiClic/src/org/pticlic/Information.java @@ -40,7 +40,7 @@ public class Information extends Activity { } in.close(); - webview.loadUrl("http://www.pticlic.fr/html5/code/html5/"); + webview.loadData(html, "text/html", "UTF-8"); } catch (IOException e) { //TODO : Ajouter un boite de dialog indiquant qu'une erreur est arrivee. diff --git a/code/PtiClic/src/org/pticlic/games/BaseGame.java b/code/PtiClic/src/org/pticlic/games/BaseGame.java deleted file mode 100644 index ee966ed..0000000 --- a/code/PtiClic/src/org/pticlic/games/BaseGame.java +++ /dev/null @@ -1,433 +0,0 @@ -package org.pticlic.games; - -import org.pticlic.R; -import org.pticlic.BaseScore; -import org.pticlic.exception.PtiClicException; -import org.pticlic.model.Constant; -import org.pticlic.model.DownloadedBaseGame; -import org.pticlic.model.Match; -import org.pticlic.model.Network; -import org.pticlic.model.Network.Mode; -import org.pticlic.model.Relation; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.Display; -import android.view.Gravity; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.animation.AlphaAnimation; -import android.view.animation.AnimationSet; -import android.view.animation.TranslateAnimation; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.LinearLayout.LayoutParams; -import android.widget.TextView; - -import com.google.gson.Gson; - -/** - * @author Bertrand BRUN et Georges DUPÉRON - * - * Cette classe est le controlleur du premier jeu. - * - * Ce premier jeu appeler "Jeux de Base", permet de creer des relations en selectionnant - * le type de relation d'un mot du nuage de mot par rapport au mot central. - * - * La vue de ce jeu se presente sous la forme d'un fenetre presentant en haut le mot central, - * et les mots du nuage descende en partant du mot central vers le centre du mobile. - * Une fois le mot du nuage afficher, l'utilisateur peut selectionner, parmis les relations - * proposer celle qui lui semble le mieux approprier. - * - */ - -public class BaseGame extends Activity implements OnClickListener { - private int currentWord = 0; - private TextView currentWordTextView; - private TextView wordRemaining; - private int nbWord = 0; - private DownloadedBaseGame game; - private Match match; - private Network network; - private boolean help = false; - private String gameJson; - - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.basegame); - - // On recupere du PreferenceManager les differentes information dont on a besoin - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - String serverURL = sp.getString(Constant.SERVER_URL, Constant.SERVER); - String id = sp.getString(Constant.USER_ID, "joueur"); - String passwd = sp.getString(Constant.USER_PASSWD, ""); - gameJson = sp.getString(Constant.NEW_BASE_GAME, null); - - // On initialise la classe permettant la communication avec le serveur. - network = new Network(serverURL, Mode.SIMPLE_GAME, id, passwd); - } - - - - /* (non-Javadoc) - * @see android.app.Activity#onStart() - */ - @Override - protected void onStart() { - super.onStart(); - try { - Gson gson = new Gson(); - if (gameJson == null) game = (DownloadedBaseGame)network.getGames(1); - else game = gson.fromJson(gameJson, DownloadedBaseGame.class); - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - Boolean first = sp.getBoolean(Constant.FIRST_TIME, true); - if (first) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.basegame_title)) - .setIcon(android.R.drawable.ic_dialog_info) - .setMessage(getString(R.string.basegame_explication)) - .setCancelable(false) - .setNegativeButton("Fermez", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - runMatch(); - start(); - } - }) - .setPositiveButton("Ne plus afficher", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - sp.edit().putBoolean(Constant.FIRST_TIME, false).commit(); - dialog.cancel(); - runMatch(); - start(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } else { - runMatch(); - start(); - } - } catch (PtiClicException e) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(e.getMessage()) - .setCancelable(false) - .setNegativeButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - finish(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } catch (Exception e) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.app_name)) - .setIcon(android.R.drawable.ic_dialog_alert) - .setMessage(getString(R.string.server_down)) - .setCancelable(false) - .setNegativeButton("Ok", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - finish(); - } - }); - AlertDialog alert = builder.create(); - alert.show(); - } - - } - - private void runMatch() { - nbWord = game.getNbWord(); - - wordRemaining = (TextView)findViewById(R.id.wordRemaining); - wordRemaining.setText((currentWord + 1) + "/" + nbWord); - - // On initialise la partie. - match = new Match(); - match.setGame(game); - - // Boutons des relations - ImageView r1 = ((ImageView)findViewById(R.id.relation1)); - ImageView r2 = ((ImageView)findViewById(R.id.relation2)); - ImageView r3 = ((ImageView)findViewById(R.id.relation3)); - ImageView r4 = ((ImageView)findViewById(R.id.relation4)); - - - // TextView des relations - TextView rn1 = ((TextView)findViewById(R.id.relation1Name)); - TextView rn2 = ((TextView)findViewById(R.id.relation2Name)); - TextView rn3 = ((TextView)findViewById(R.id.relation3Name)); - TextView rn4 = ((TextView)findViewById(R.id.relation4Name)); - - // Bouton d'aide - ImageView aide = ((ImageView)findViewById(R.id.aideBaseGame)); - aide.setOnClickListener(this); - - // On met set le nom du mot central - ((TextView)findViewById(R.id.mainWord)).setText(DownloadedBaseGame.getName(game.getCentre())); - - Relation r = Relation.getInstance(); - - // Écoute des clics sur les relations - // TODO : A enlever lorsque l'on aura toutes les images des relations. - try { - r1.setOnClickListener(this); - rn1.setText(String.format(r.getRelationName(game.getCat1()), ((TextView)findViewById(R.id.mainWord)).getText())); - r1.setImageResource(r.getRelationImage(game.getCat1())); - } catch (Exception e) { - r1.setImageResource(R.drawable.icon); - } - // TODO : A enlever lorsque l'on aura toutes les images des relations. - try { - r2.setOnClickListener(this); - rn2.setText(String.format(r.getRelationName(game.getCat2()), ((TextView)findViewById(R.id.mainWord)).getText())); - r2.setImageResource(r.getRelationImage(game.getCat2())); - } catch (Exception e) { - r2.setImageResource(R.drawable.icon); - } - // TODO : A enlever lorsque l'on aura toutes les images des relations. - try { - r3.setOnClickListener(this); - rn3.setText(String.format(r.getRelationName(game.getCat3()), ((TextView)findViewById(R.id.mainWord)).getText())); - r3.setImageResource(r.getRelationImage(game.getCat3())); - } catch (Exception e) { - r3.setImageResource(R.drawable.icon); - } - // TODO : A enlever lorsque l'on aura toutes les images des relations. - try { - r4.setOnClickListener(this); - rn4.setText(String.format(r.getRelationName(game.getCat4()), ((TextView)findViewById(R.id.mainWord)).getText())); - r4.setImageResource(r.getRelationImage(game.getCat4())); - } catch (Exception e) { - r4.setImageResource(R.drawable.icon); - } - - this.helpMode(); - } - - /* (non-Javadoc) - * @see android.app.Activity#onActivityResult(int, int, android.content.Intent) - */ - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - finish(); - } - - /** - * Cette methode permet au mot courant de partir du mot central vers le centre de l'appareil. - */ - private void arrivalView() { - //On recupere la largueur de l'ecran. - Display display = getWindowManager().getDefaultDisplay(); - int width = display.getWidth(); - - // On recupere le centre de mainWord pour l'animation de translation. - TextView mainWord = (TextView)findViewById(R.id.mainWord); - currentWordTextView = (TextView)findViewById(R.id.currentWord); - - // On defini un ensemble d'animation - AnimationSet set = new AnimationSet(true); - set.setDuration(1000); - set.setFillAfter(true); - - TranslateAnimation translate; - if (isInHelpMode()) - translate = new TranslateAnimation(mainWord.getScrollX() / 2, mainWord.getScrollX() / 2, mainWord.getScrollY() / 2, width / 8); - else - translate = new TranslateAnimation(mainWord.getScrollX() / 2, mainWord.getScrollX() / 2, mainWord.getScrollY() / 2, width / 4); - translate.setDuration(500); - set.addAnimation(translate); - - AlphaAnimation alpha = new AlphaAnimation(0, 1); - alpha.setDuration(1000); - set.addAnimation(alpha); - - // Que l'on rajoute a notre vue. - currentWordTextView.startAnimation(set); - } - - /** - * - */ - private void leaveView() { - currentWordTextView.clearAnimation(); - } - - /** - * Cette methode permet de passer au mot courant suivant et de lancer l'animation. - */ - private void start() { - ((TextView)findViewById(R.id.currentWord)).setText(DownloadedBaseGame.getName(game.getWordInCloud(currentWord))); - arrivalView(); - } - - /** - * Permet de verifier si la partie est fini auquel cas on lance l'activite Score, sinon on passe au mot suivant. - */ - private void next() { - if (++currentWord < nbWord) { - wordRemaining.setText((currentWord + 1) + "/" + nbWord); - leaveView(); - start(); - } else { - Intent intent = new Intent(this, BaseScore.class); - intent.putExtra(Constant.SCORE_GAMEPLAYED, match); - intent.putExtra(Constant.SCORE_MODE, Mode.SIMPLE_GAME); - - startActivityForResult(intent, 0x100); - } - } - - /** - * Cette methode est appeler lorsque l'utilisateur appuie sur le bouton d'aide. - * Elle change la disposition des elements de maniere a afficher la description - * de l'icone a cote de l'icone. - */ - private void helpMode() { - if (!isInHelpMode()) { - help = true; - - LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 2); - - // On modifie l'affichage du layout - LinearLayout menuLayout = ((LinearLayout)findViewById(R.id.menuLayout)); - menuLayout.setOrientation(LinearLayout.VERTICAL); - menuLayout.setLayoutParams(layoutParams); - - // Puis on modifie l'affichage des relations - //relation1 - LinearLayout relationLayout = ((LinearLayout)findViewById(R.id.relation1Layout)); - relationLayout.setGravity(Gravity.LEFT); - - TextView relationName = ((TextView)findViewById(R.id.relation1Name)); - relationName.setVisibility(View.VISIBLE); - - //relation2 - relationLayout = ((LinearLayout)findViewById(R.id.relation2Layout)); - relationLayout.setGravity(Gravity.LEFT); - - relationName = ((TextView)findViewById(R.id.relation2Name)); - relationName.setVisibility(View.VISIBLE); - - //relation3 - relationLayout = ((LinearLayout)findViewById(R.id.relation3Layout)); - relationLayout.setGravity(Gravity.LEFT); - - relationName = ((TextView)findViewById(R.id.relation3Name)); - relationName.setVisibility(View.VISIBLE); - - //relation4 - relationLayout = ((LinearLayout)findViewById(R.id.relation4Layout)); - relationLayout.setGravity(Gravity.LEFT); - - relationName = ((TextView)findViewById(R.id.relation4Name)); - relationName.setVisibility(View.VISIBLE); - - - // On met le mot courant au bon endroit dans la fenetre - // On recupere la largueur de l'ecran. - Display display = getWindowManager().getDefaultDisplay(); - int width = display.getWidth(); - - //On recupere le centre de mainWord pour l'animation de translation. - TextView mainWord = (TextView)findViewById(R.id.mainWord); - currentWordTextView = (TextView)findViewById(R.id.currentWord); - - TranslateAnimation translate = new TranslateAnimation(mainWord.getScrollX() / 2, mainWord.getScrollX() / 2, mainWord.getScrollY() / 2, width / 8); - translate.setDuration(0); - translate.setFillAfter(true); - - currentWordTextView.setAnimation(translate); - - } else { - help = false; - - LayoutParams layoutParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 10); - - // On modifie l'affichage du layout - LinearLayout menuLayout = ((LinearLayout)findViewById(R.id.menuLayout)); - menuLayout.setOrientation(LinearLayout.HORIZONTAL); - menuLayout.setLayoutParams(layoutParams); - - // Puis on modifie l'affichage des relations - //relation1 - LinearLayout relationLayout = ((LinearLayout)findViewById(R.id.relation1Layout)); - relationLayout.setGravity(Gravity.CENTER); - - TextView relationName = ((TextView)findViewById(R.id.relation1Name)); - relationName.setVisibility(View.GONE); - - //relation2 - relationLayout = ((LinearLayout)findViewById(R.id.relation2Layout)); - relationLayout.setGravity(Gravity.CENTER); - - relationName = ((TextView)findViewById(R.id.relation2Name)); - relationName.setVisibility(View.GONE); - - //relation3 - relationLayout = ((LinearLayout)findViewById(R.id.relation3Layout)); - relationLayout.setGravity(Gravity.CENTER); - - relationName = ((TextView)findViewById(R.id.relation3Name)); - relationName.setVisibility(View.GONE); - - //relation4 - relationLayout = ((LinearLayout)findViewById(R.id.relation4Layout)); - relationLayout.setGravity(Gravity.CENTER); - - relationName = ((TextView)findViewById(R.id.relation4Name)); - relationName.setVisibility(View.GONE); - - // On met le mot courant au bon endroit dans la fenetre - // On recupere la largueur de l'ecran. - Display display = getWindowManager().getDefaultDisplay(); - int width = display.getWidth(); - - //On recupere le centre de mainWord pour l'animation de translation. - TextView mainWord = (TextView)findViewById(R.id.mainWord); - currentWordTextView = (TextView)findViewById(R.id.currentWord); - - TranslateAnimation translate = new TranslateAnimation(mainWord.getScrollX() / 2, mainWord.getScrollX() / 2, mainWord.getScrollY() / 2, width / 4); - translate.setDuration(0); - translate.setFillAfter(true); - - currentWordTextView.setAnimation(translate); - } - } - - /** - * Permet de savoir si l'on se trouve ou non dans le mode d'aide - * - * @return true si l'on ce trouve dans le mode d'aide false sinon - */ - private boolean isInHelpMode() { - return help; - } - - /* (non-Javadoc) - * @see android.view.View.OnClickListener#onClick(android.view.View) - */ - @Override - public void onClick(View v) { - switch (v.getId()) { - case (R.id.relation1) : match.add(1, currentWord); next(); break; - case (R.id.relation2) : match.add(2, currentWord); next(); break; - case (R.id.relation3) : match.add(3, currentWord); next(); break; - case (R.id.relation4) : match.add(4, currentWord); next(); break; - case (R.id.aideBaseGame) : helpMode(); break; - } - } -} \ No newline at end of file diff --git a/code/PtiClic/src/org/pticlic/model/Constant.java b/code/PtiClic/src/org/pticlic/model/Constant.java index d4a3b54..27481ce 100644 --- a/code/PtiClic/src/org/pticlic/model/Constant.java +++ b/code/PtiClic/src/org/pticlic/model/Constant.java @@ -1,7 +1,7 @@ package org.pticlic.model; public class Constant { - public static final String SERVER_URL = "server"; + public static final String SERVER_URL = "html5/code/html5/"; public static final String SERVER_AUTH = "SERVER_AUTH"; public static final String SERVER = "http://www.pticlic.fr/"; diff --git a/code/PtiClic/src/org/pticlic/model/DownloadedBaseGame.java b/code/PtiClic/src/org/pticlic/model/DownloadedBaseGame.java deleted file mode 100644 index 9c3b048..0000000 --- a/code/PtiClic/src/org/pticlic/model/DownloadedBaseGame.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.pticlic.model; - -import java.io.Serializable; -import java.util.Arrays; - -/** - * @author Bertrand BRUN - * - * Classe metier reprensentant une parti "Normal" telecharge. - */ -public class DownloadedBaseGame extends DownloadedGame { - - private static final long serialVersionUID = 1L; - - public static class Word implements Serializable { - - private static final long serialVersionUID = 1L; - private int id; - private String name; - - public Word() {} - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - } - - private int cat1; - private int cat2; - private int cat3; - private int cat4; - private Word center; - private Word[] cloud; - - public DownloadedBaseGame() { - super(); - this.cat1 = -1; - this.cat2 = -1; - this.cat3 = -1; - this.cat4 = -1; - this.center = null; - this.cloud = null; - } - - public DownloadedBaseGame(int id, int gid, int pgid, int cat1, int cat2, - int cat3, int cat4, Word center, Word[] cloud) { - super(id, gid, pgid); - this.cat1 = cat1; - this.cat2 = cat2; - this.cat3 = cat3; - this.cat4 = cat4; - this.center = center; - this.cloud = cloud; - } - - public static String getName(Word word) { - return word.getName(); - } - - public int getCat(int numCat) { - switch (numCat) { - case 1: return getCat1(); - case 2: return getCat2(); - case 3: return getCat3(); - default: return getCat4(); - } - } - - public String getCatString(int numCat) { - return String.format( - Relation.getInstance().getRelationName(this.getCat(numCat)), - center.getName()); - } - - public int getCat1() { - return cat1; - } - - public void setCat1(int cat1) { - this.cat1 = cat1; - } - - public int getCat2() { - return cat2; - } - - public void setCat2(int cat2) { - this.cat2 = cat2; - } - - public int getCat3() { - return cat3; - } - - public void setCat3(int cat3) { - this.cat3 = cat3; - } - - public int getCat4() { - return cat4; - } - - public void setCat4(int cat4) { - this.cat4 = cat4; - } - - public Word getCentre() { - return center; - } - - public void setCentre(Word center) { - this.center = center; - } - - public int getNbWord() { - return cloud.length; - } - - public Word getWordInCloud(int index) { - return cloud[index]; - } - - - @Override - public String toString() { - return "DownloadedBaseGame [gid=" + gid + ", pgid=" + pgid + ", id=" + id - + ", cat1=" + cat1 + ", cat2=" + cat2 + ", cat3=" + cat3 - + ", cat4=" + cat4 + ", center=" + center + ", cloud=" - + Arrays.toString(cloud) + "]"; - } - -} diff --git a/code/PtiClic/src/org/pticlic/model/DownloadedGame.java b/code/PtiClic/src/org/pticlic/model/DownloadedGame.java deleted file mode 100644 index 1b21133..0000000 --- a/code/PtiClic/src/org/pticlic/model/DownloadedGame.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.pticlic.model; - -import java.io.Serializable; - - -/** - * @author Bertrand BRUN - * - * Classe metier reprensentant n'importe quel le jeu telecharger du serveur. - * - */ -public abstract class DownloadedGame implements Serializable { - - private static final long serialVersionUID = 1L; - - protected int gid; - protected int pgid; - protected int id; - - public DownloadedGame() { - this.id = -1; - this.gid = -1; - this.pgid = -1; - } - - public DownloadedGame(int id, int gid, int pgid) { - super(); - this.id = id; - this.gid = gid; - this.pgid = pgid; - } - - public int getGid() { - return gid; - } - - public void setGid(int gid) { - this.gid = gid; - } - - public int getPgid() { - return pgid; - } - - public void setPgid(int pgid) { - this.pgid = pgid; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - -} diff --git a/code/PtiClic/src/org/pticlic/model/Match.java b/code/PtiClic/src/org/pticlic/model/Match.java deleted file mode 100644 index 5aaba36..0000000 --- a/code/PtiClic/src/org/pticlic/model/Match.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.pticlic.model; - -import java.io.Serializable; -import java.util.ArrayList; - -/** - * @author Bertrand BRUN - * - * Cette classe represente une partie joue. - * Elle sera envoyer au serveur pour que celui-ci - * puisse calculer le score obtenue. - * - */ -public class Match implements Serializable { - - private static final long serialVersionUID = 1L; - private ArrayList relation1; - private ArrayList relation2; - private ArrayList relation3; - private ArrayList relation4; - private DownloadedGame game; - - public Match() { - relation1 = new ArrayList(); - relation2 = new ArrayList(); - relation3 = new ArrayList(); - relation4 = new ArrayList(); - } - - public void setGame(DownloadedGame game) { - this.game = game; - } - - public DownloadedGame getGame() { - return game; - } - - public void add(int relation, int word) { - switch (relation) { - case 1: relation1.add(word); break; - case 2: relation2.add(word); break; - case 3: relation3.add(word); break; - case 4: relation4.add(word); break; - } - } - - /** - * @return the relation1 - */ - public ArrayList getRelation1() { - return relation1; - } - - /** - * @return the relation2 - */ - public ArrayList getRelation2() { - return relation2; - } - - /** - * @return the relation3 - */ - public ArrayList getRelation3() { - return relation3; - } - - /** - * @return the relation4 - */ - public ArrayList getRelation4() { - return relation4; - } -} diff --git a/code/PtiClic/src/org/pticlic/model/Network.java b/code/PtiClic/src/org/pticlic/model/Network.java index 9fdbd73..c04377a 100644 --- a/code/PtiClic/src/org/pticlic/model/Network.java +++ b/code/PtiClic/src/org/pticlic/model/Network.java @@ -1,13 +1,6 @@ package org.pticlic.model; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.Serializable; -import java.io.UnsupportedEncodingException; - -import org.pticlic.exception.PtiClicException; import android.content.Context; import android.content.SharedPreferences; @@ -15,7 +8,6 @@ import android.net.ConnectivityManager; import android.preference.PreferenceManager; import com.google.gson.Gson; -import com.google.gson.stream.JsonReader; /** @@ -175,179 +167,4 @@ public class Network { return res; } - - /** - * Cette méthode permet de récupérer du serveur un certain nombre de parties. - * @param nbGames Le nombre de parties que l'on veut récupérer. - * @return - */ - public DownloadedGame getGames(int nbGames) throws PtiClicException, Exception { - switch (mode) { - case SIMPLE_GAME: - return DownloadBaseGame(nbGames); - default: - return null; - } - } - - private DownloadedBaseGame DownloadBaseGame(int nbGames) throws PtiClicException, Exception { - Gson gson = null; - String json = null; - DownloadedBaseGame game = null; - - // URLConnection connection = url.openConnection(); - // connection.addRequestProperty("action", Action.GET_GAMES.value()); - // connection.addRequestProperty("user", this.id); - // connection.addRequestProperty("passwd", this.passwd); - // connection.addRequestProperty("nb", String.valueOf(nbGames)); - // connection.addRequestProperty("mode", mode.value()); - - String urlS = this.serverURL - + "?action=" + Action.GET_GAMES.value() - + "&user=" + this.id - + "&passwd=" + this.passwd - + "&nb=" + String.valueOf(nbGames) - + "&mode="+mode.value(); - - gson = new Gson(); - json = HttpClient.SendHttpPost(urlS); - - try { - - //JsonReader reader = new JsonReader(new InputStreamReader(connection.getInputStream(), "UTF-8")); - InputStream in = new ByteArrayInputStream(json.getBytes("UTF-8")); - JsonReader jsonReader = new JsonReader(new InputStreamReader(in)); - - // FIXME : Attention lorsque l'on pourra vraiment recupere plusieur partie, il faudra changer ce qui suit. - jsonReader.beginArray(); - while (jsonReader.hasNext()) { - game = makeBaseGame(jsonReader, gson); - } - jsonReader.endArray(); - jsonReader.close(); - } catch (UnsupportedEncodingException e1) { - throw new PtiClicException(0, "Impossible de recuperer l'erreur, nous avons pris note de cette erreur.\n Merci"); - } catch (IOException e1) { - throw new PtiClicException(0, "Impossible de recuperer l'erreur, nous avons pris note de cette erreur.\n Merci"); - } catch (Exception e) { - throw new PtiClicException(json); - } - - return game; - } - - /** - * Permet la transformation du Json en une instance de Game. - * - * @param reader Le Json sous forme d'un flux. - * @param gson Une instance de Gson. - * @return Une nouvelle instance de Game. - * @throws IOException - */ - private DownloadedBaseGame makeBaseGame(JsonReader reader, Gson gson) throws IOException { - int gid = -1; - int pgid = -1; - int id = -1; - int cat1 = -1; - int cat2 = -1; - int cat3 = -1; - int cat4 = -1; - DownloadedBaseGame.Word center = null; - DownloadedBaseGame.Word[] cloud = null; - - reader.beginObject(); - while (reader.hasNext()) { - String name = reader.nextName(); - if (name.equals("id")) { - id = reader.nextInt(); - } else if (name.equals("gid")) { - gid = reader.nextInt(); - } else if (name.equals("pgid")) { - pgid = reader.nextInt(); - } else if (name.equals("cat1")) { - cat1 = reader.nextInt(); - } else if (name.equals("cat2")) { - cat2 = reader.nextInt(); - } else if (name.equals("cat3")) { - cat3 = reader.nextInt(); - } else if (name.equals("cat4")) { - cat4 = reader.nextInt(); - } else if (name.equals("center")) { - center = gson.fromJson(reader, DownloadedBaseGame.Word.class); - } else if (name.equals("cloud")) { - cloud = gson.fromJson(reader, DownloadedBaseGame.Word[].class); - } else { - reader.skipValue(); - } - } - reader.endObject(); - return new DownloadedBaseGame(id, gid, pgid, cat1, cat2, cat3, cat4, center, cloud); - } - - /** - * Cette méthode permet d'envoyer les parties au serveur pour qu'il puisse les - * rajouter à la base de données, et calculer le score. - * @param game La partie jouee par l'utilisateur - * @return Le score sous forme JSON. - */ - public ScoreResponse sendGame(Match game) throws PtiClicException, Exception { - switch (mode) { - case SIMPLE_GAME: - return sendBaseGame(game); - default: - return null; - } - } - - public ScoreResponse sendBaseGame(Match game) throws PtiClicException, Exception { - Gson gson = null; - String json = null; - - // TODO : ne restera le temps que les requete du serveur passe du GET au POST - String urlS = this.serverURL - + "?action=" + Action.SEND_GAME.value() - + "&user=" + this.id - + "&passwd=" + this.passwd - + "&pgid=" + game.getGame().getPgid() - + "&gid=" + game.getGame().getGid() - + "&mode="+mode.value() - + "&nb="+((DownloadedBaseGame)(game.getGame())).getNbWord(); - - // TODO : faut gere le mode - for (Integer i : game.getRelation1()) { - urlS += "&" + i + "=" + ((DownloadedBaseGame)game.getGame()).getCat1() ; - } - for (Integer i : game.getRelation2()) { - urlS += "&" + i + "=" + ((DownloadedBaseGame)game.getGame()).getCat2(); - } - for (Integer i : game.getRelation3()) { - urlS += "&" + i + "=" + ((DownloadedBaseGame)game.getGame()).getCat3(); - } - for (Integer i : game.getRelation4()) { - urlS += "&" + i + "=" + ((DownloadedBaseGame)game.getGame()).getCat4(); - } - - // URL url = new URL(this.serverURL); // Attention ! this.serverURL contient "/server.php" - // URLConnection connection = url.openConnection(); - // connection.addRequestProperty("action", Action.SEND_GAME.value()); - // connection.addRequestProperty("user", this.id); - // connection.addRequestProperty("passwd", this.passwd); - // connection.addRequestProperty("mode", mode.value()); - // connection.addRequestProperty("pgid", String.valueOf(game.getGame().getId())); - - gson = new Gson(); - json = HttpClient.SendHttpPost(urlS); - - // Comme gson ne renvoie pas une erreur si l'objet qui recupere ne correspond pas a la classe qu'il attends. - // On creer tout d'abord une objet error et si celui-ci est vide on creer l'objet score, sinon on lance - // une exception. - int foo = 42; - ScoreResponse sr = gson.fromJson(json, ScoreResponse.class); - foo = foo + 1; - if (sr.getNewGame() == null) { - throw new PtiClicException(gson.fromJson(json, PtiClicException.Error.class)); - } else { - return sr; - } - } } diff --git a/code/PtiClic/src/org/pticlic/model/Relation.java b/code/PtiClic/src/org/pticlic/model/Relation.java deleted file mode 100644 index a06bf7f..0000000 --- a/code/PtiClic/src/org/pticlic/model/Relation.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.pticlic.model; - -import java.util.HashMap; - -import org.pticlic.R; - -/** - * @author Bertrand BRUN - * - * Cette classe permet de recuperer le noms ou l'image d'un relation en fonction du numero de son id. - * - */ -public class Relation { - // TODO : Penser a peut etre remplacer les HashMap par une BDD. - - private static Relation instance = null; - - HashMap stringRelations; - HashMap imageRelations; - - private Relation() { - imageRelations = new HashMap(); - imageRelations.put(-1, R.drawable.corbeille); - imageRelations.put(0, R.drawable.rapport); - imageRelations.put(5, R.drawable.synonyme); - imageRelations.put(7, R.drawable.contraire); - imageRelations.put(9, R.drawable.contenu); - imageRelations.put(10, R.drawable.contenant); - - // ATTENTION ! Tout ce qui est ci-dessous est en double dans relations.php . - stringRelations = new HashMap(); - stringRelations.put(-1, "Mot non lié à '%s'"); - stringRelations.put(0, "'%s' est en rapport avec..."); - stringRelations.put(1, "raffinement sémantique"); // pas utilisé - stringRelations.put(2, "raffinement morphologique"); // pas utilisé - stringRelations.put(3, "domaine"); // pas utilisé - stringRelations.put(4, "r_pos"); // pas utilisé - stringRelations.put(5, "'%s' est un synonyme de..."); - stringRelations.put(6, "'%s' est une sorte de..."); - stringRelations.put(7, "Un contraire de '%s' est..."); - stringRelations.put(8, "Un spécifique de '%s' est..."); - stringRelations.put(9, "... est une partie de '%s'"); - stringRelations.put(10, "'%s' fait partie de..."); - stringRelations.put(11, "locution"); // pas utilisé - stringRelations.put(12, "potentiel de FL"); // pas utilisé - stringRelations.put(13, "Quoi/Qui pourrait '%s'"); - stringRelations.put(14, "action>patient"); // pas utilisé - stringRelations.put(15, "Le lieu pour '%s' est..."); - stringRelations.put(16, "Un instrument pour '%s' est..."); - stringRelations.put(17, "Un caractéristique de '%s' est..."); - stringRelations.put(18, "r_data"); // pas utilisé - stringRelations.put(19, "r_lemma"); // pas utilisé - stringRelations.put(20, "magn"); // pas utilisé - stringRelations.put(21, "antimagn"); // pas utilisé - stringRelations.put(22, "'%s' est de la même famille que..."); - stringRelations.put(29, "predicat"); // pas utilisé - stringRelations.put(30, "lieu>action"); // pas utilisé - stringRelations.put(31, "action>lieu"); // pas utilisé - stringRelations.put(32, "sentiment"); // pas utilisé - stringRelations.put(33, "erreur"); // pas utilisé - stringRelations.put(34, "manière"); // pas utilisé - stringRelations.put(35, "sens/signification"); // pas utilisé - stringRelations.put(36, "information potentielle"); // pas utilisé - stringRelations.put(37, "rôle télique"); // pas utilisé - stringRelations.put(38, "rôle agentif"); // pas utilisé - stringRelations.put(41, "conséquence"); // pas utilisé - stringRelations.put(42, "cause"); // pas utilisé - stringRelations.put(52, "succession"); // pas utilisé - stringRelations.put(53, "produit"); // pas utilisé - stringRelations.put(54, "est le produit de"); // pas utilisé - stringRelations.put(55, "s'oppose à"); // pas utilisé - } - - public synchronized static Relation getInstance() { - if (instance == null) { - instance = new Relation(); - } - return instance; - } - - public String getRelationName(int id) { - return stringRelations.get(id); - } - - public Integer getRelationImage(int id) { - return imageRelations.get(id); - } -} From d07d3b03c935e4aa0c54d4b032c5d989af86e513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Tue, 5 Apr 2011 18:38:58 +0200 Subject: [PATCH 10/20] Ajout des boutons de relations dans le .jss . --- code/html5/index.html | 52 ++++++++----------------------------- code/html5/pticlic.js | 60 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 66 insertions(+), 46 deletions(-) diff --git a/code/html5/index.html b/code/html5/index.html index febff8d..dc2a777 100644 --- a/code/html5/index.html +++ b/code/html5/index.html @@ -6,9 +6,6 @@ - - +.relations .rid0 { background-image: url("img/rel/0.png"); } +.relations .rid5 { background-image: url("img/rel/5.png"); } +.relations .rid7 { background-image: url("img/rel/7.png"); } +.relations .rid9 { background-image: url("img/rel/9.png"); } +.relations .rid10 { background-image: url("img/rel/10.png"); } + +.relations .hot { + background-color: yellow; +} + @@ -85,7 +55,7 @@ body {
- +
diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index a4dfe98..f5dc7cc 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -1,31 +1,78 @@ function jss() { var w=480, h=800; var mch = h/8, mnh = h*0.075; + + $("body") + .css({ + padding: 0, + margin: 0, + textAlign: "left" + }); + $("#screen") .width(w) .height(h) + .position({my:"center center", at:"center center", of:"body", collision:"none"}); $("#mc-caption-block") + .css({ + position: "absolute" + }) .width(w) .height(mch) .position({my:"center top", at:"center top", of:"#screen", collision:"none"}); + $("#mc-caption") + .css({ + maxWidth: w*0.9, + textAlign: "center", + position: "absolute" + }) .fitFont(w*0.9, mch*0.9, 20) - .css("max-width", w*0.9) .position({my:"center center", at:"center center", of:"#mc-caption-block", collision:"none"}); $("#mn-caption-block") + .css({ + borderWidth: h/100, + position: "absolute" + }) .width(w) .height(mnh) - .css("border-width", h/100) .position({my:"center top", at:"center bottom", of:"#mc-caption-block", collision:"none"}); + $("#mn-caption") + .css({ + maxWidth: w*0.9, + textAlign: "center", + position: "absolute" + }) .fitFont(w*0.9, mnh*0.9, 20) - .css("max-width", w*0.9) .position({my:"center center", at:"center center", of:"#mn-caption-block", collision:"none"}); + + $(".relations > div") + .css({ + margin: 10, + height: 72, + padding: 10, + }); - $("#screen") - .position({my:"center center", at:"center center", of:"body", collision:"none"}); + // TODO : fitFont pour ".relations div" + $(".relations > div:nth-child(odd)") + .css({ + backgroundPosition: "2% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. + textAlign: "right", + paddingLeft: 76 + }); + + $(".relations > div:nth-child(even)") + .css({ + backgroundPosition: "98% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. + textAlign: "left", + paddingRight: 76 + }); + + $(".relations") + .position({my:"center bottom", at:"center bottom", of:"#screen", offset:"0 -10", collision:"none"}); } @@ -53,11 +100,14 @@ $(function () { .addClass("rid"+cat.id) .click(function() { answers[currentWordNb++] = cat.id; + $(this).addClass("hot")//.delay(500).removeClass("hot"); // TODO: just blink. refresh(); }) .appendTo(".relations"); }); + $(window).resize(jss); refresh(); + refresh(); // TODO : fix the bug with the margin on ".relation > div" }); }); From 4bc59ed81c5b949d1594455444ad76e7eb1bc2af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Wed, 6 Apr 2011 11:53:56 +0200 Subject: [PATCH 11/20] Refactor du jss. --- code/html5/my-extensions.js | 54 +++++++++++++++++++++++++++++++++++++ code/html5/pticlic.js | 40 +++++++++++++-------------- 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/code/html5/my-extensions.js b/code/html5/my-extensions.js index 827f980..abd2101 100644 --- a/code/html5/my-extensions.js +++ b/code/html5/my-extensions.js @@ -33,3 +33,57 @@ $.fn.fitFont = function(w, h, minFont, maxFont) { e.css("position", oldpos); return e; } + +function queueize(method) { + return function() { + var that = $(this); + var args = arguments; + return that.queue(function(next) { + that[method].apply(that,args); + next(); + }); + }; +} + +$.fn.qAddClass = queueize("addClass"); +$.fn.qRemoveClass = queueize("removeClass"); + +$.fn.wh = function(w, h) { + return $(this).width(w).height(h); +} + +$.fn.relativePos = function(xAnchor, yAnchor, to) { + var that = $(this); + var deltaX = that.width() * xAnchor; + var deltaY = that.height() * yAnchor; + + if (to) { + that.css("position", "absolute"); + that.offset({ + left: to.left - deltaX, + top: to.top - deltaY + }); + return that; + } else { + var pos = that.offset(); + pos.left += deltaX; + pos.top += deltaY; + return pos; + } +}; + +$.each({ + center: {x:0.5, y:0.5}, + north: {x:0.5, y:0}, + northEast: {x:1, y:0}, + east: {x:1, y:0.5}, + southEast: {x:1, y:1}, + south: {x:0.5, y:1}, + southWest: {x:0, y:1}, + west: {x:0, y:0.5}, + northWest: {x:0, y:0}, +}, function(i,e) { + var x = e.x; + var y = e.y; + $.fn[i] = function(to) { return $(this).relativePos(x, y, to); }; +}); diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index f5dc7cc..d6c2e44 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -10,44 +10,38 @@ function jss() { }); $("#screen") - .width(w) - .height(h) - .position({my:"center center", at:"center center", of:"body", collision:"none"}); + .wh(w, h) + .north($("body").north()); // TODO : par rapport à la fenêtre entière.0 $("#mc-caption-block") - .css({ - position: "absolute" - }) - .width(w) - .height(mch) - .position({my:"center top", at:"center top", of:"#screen", collision:"none"}); + .wh(w, mch) + .north($("#screen").north()); $("#mc-caption") .css({ maxWidth: w*0.9, - textAlign: "center", - position: "absolute" + textAlign: "center" }) .fitFont(w*0.9, mch*0.9, 20) - .position({my:"center center", at:"center center", of:"#mc-caption-block", collision:"none"}); + .center($("#mc-caption-block").center()); $("#mn-caption-block") .css({ borderWidth: h/100, position: "absolute" }) - .width(w) - .height(mnh) - .position({my:"center top", at:"center bottom", of:"#mc-caption-block", collision:"none"}); + .wh(w, mnh) + .north($("#mc-caption-block").south()); $("#mn-caption") .css({ maxWidth: w*0.9, textAlign: "center", - position: "absolute" + position: "absolute", + zIndex: 10 }) .fitFont(w*0.9, mnh*0.9, 20) - .position({my:"center center", at:"center center", of:"#mn-caption-block", collision:"none"}); + .center($("#mn-caption-block").center()); $(".relations > div") .css({ @@ -72,7 +66,13 @@ function jss() { }); $(".relations") - .position({my:"center bottom", at:"center bottom", of:"#screen", offset:"0 -10", collision:"none"}); + .south($("#screen").south()); +} + +function animateNext(e, button) { + console.log(e, e.clientX, e.clientY); + $(button).qAddClass("hot").delay(100).qRemoveClass("hot"); + $("#mn-caption").animate({left:e.clientX, top:e.clientY},1500); } @@ -98,9 +98,9 @@ $(function () { $('
') .html(cat.name.replace(/%(m[cn])/g, '')) .addClass("rid"+cat.id) - .click(function() { + .click(function(e) { answers[currentWordNb++] = cat.id; - $(this).addClass("hot")//.delay(500).removeClass("hot"); // TODO: just blink. + animateNext(e, this); refresh(); }) .appendTo(".relations"); From 1327ccfcb6868b1dd7da50668dacb01919e66c04 Mon Sep 17 00:00:00 2001 From: Bertrand BRUN Date: Wed, 6 Apr 2011 11:55:33 +0200 Subject: [PATCH 12/20] Refactoring du SQL et des Exception --- code/serveur/php/pticlic.php | 82 +++++++---------- code/serveur/php/ressources/errors.inc | 39 ++++++++ code/serveur/php/ressources/sql.inc | 119 +++++++++++++++++++++++++ code/serveur/php/server.php | 12 +-- 4 files changed, 197 insertions(+), 55 deletions(-) create mode 100644 code/serveur/php/ressources/errors.inc create mode 100644 code/serveur/php/ressources/sql.inc diff --git a/code/serveur/php/pticlic.php b/code/serveur/php/pticlic.php index 5567ec0..5fcafea 100644 --- a/code/serveur/php/pticlic.php +++ b/code/serveur/php/pticlic.php @@ -1,6 +1,7 @@ @@ -38,7 +39,7 @@ require_once("db.php"); function checkLogin($user, $passwd) { $db = getDB(); $hashPasswd = md5($passwd); - $loginIsOk = ($hashPasswd == $db->querySingle("SELECT hash_passwd FROM user WHERE login='".$user."';")); + $loginIsOk = ($hashPasswd == $db->querySingle(sqlGetPassword($user))); return $loginIsOk; } @@ -48,7 +49,7 @@ function checkLogin($user, $passwd) { function randomCenterNode() { $db = getDB(); - return $db->querySingle("select eid from random_center_node where rowid = (abs(random()) % (select max(rowid) from random_center_node))+1;"); + return $db->querySingle(sqlGetEIDCenterNode()); } /** Selectionne aléatoirement un noeud d'un nuage. @@ -57,7 +58,7 @@ function randomCenterNode() function randomCloudNode() { $db = getDB(); - return $db->querySingle("select eid from random_cloud_node where rowid = (abs(random()) % (select max(rowid) from random_cloud_node))+1;"); + return $db->querySingle(sqlGetEIRCloudNode()); } /** @@ -73,32 +74,16 @@ function cgBuildResultSets($cloudSize, $centerEid, $r1, $r2) // Le select doit ranvoyer trois colonnes : // eid => l'eid du mot à mettre dans le nuage, // r1 => la probabilité pour que le mot soit dans r1, entre -1 et 1 (négatif = ne devrait pas y être, positif = devrait y être à coup sûr, 0 = on sait pas). - $typer1r2 = "type in ($r1, $r2)"; - $banned_types = "4, 12, 36, 18, 29, 45, 46, 47, 48, 1000, 1001"; $sources = array( - // Voisins 1 saut du bon type (= relations déjà existantes) - array('w'=>40, 'd'=>1, 's'=>"select end as eid, type = $r1 as r1, type = $r2 as r2, 0 as r0, 0 as trash from relation where start = $centerEid and $typer1r2 order by random();"), - // Voisins 1 saut via r_associated (0), donc qu'on voudrait spécifier si possible. - array('w'=>40, 'd'=>2, 's'=>"select end as eid, 0.25 as r1, 0.25 as r2, 0.5 as r0, 0 as trash from relation where start = $centerEid and type = 0 order by random();"), - // Voisins 1 saut via les autres relations - array('w'=>20, 'd'=>3.1, 's'=>"select end as eid, 0.1 as r1, 0.1 as r2, 0.8 as r0, 0 as trash from relation where start = $centerEid and type not in (0, $r1, $r2, $banned_types) order by random();"), - // Voisins 2 sauts, avec un mix de R1 et R2 pour les liens. Par ex [ A -R1-> B -R2-> C ] ou bien [ A -R2-> B -R2-> C ] - // Version optimisée de : "select end as eid from relation where $typer1r2 and start in oneHopWithType order by random();" - array('w'=>30, 'd'=>3.2, 's'=>"select B.end as eid, ((A.type = $r1) + (B.type = $r1)) / 3. as r1, ((A.type = $r2) + (B.type = $r2)) / 3. as r2, 1/6. as r0, 1/6. as trash from relation as A, relation as B where A.start = $centerEid and A.$typer1r2 and B.start = A.end and B.$typer1r2 order by random();"), - // Voisins 1 saut r1/r2 + 1 saut synonyme - // Version optimisée de : "select end as eid from relation where start in oneHopWithType and type = 5 order by random()"; - array('w'=>20, 'd'=>5, 's'=>"select B.end as eid, (A.type = $r1) * 0.75 as r1, (A.type = $r2) * 0.75 as r2, 0.25 as r0, 0 as trash from relation as A, relation as B where A.start = $centerEid and A.$typer1r2 and B.start = A.end and B.type = 5 order by random();"), - // Version optimisée de : "select end as eid from relation where start in (select end from relation where start = $centerEid and type = 5) and $typer1r2 order by random();" - array('w'=>20, 'd'=>6, 's'=>"select B.end as eid, (B.type = $r1) * 0.75 as r1, (B.type = $r2) * 0.75 as r2, 0.25 as r0, 0 as trash from relation as A, relation as B where A.start = $centerEid and A.type = 5 and B.start = A.end and B.$typer1r2 order by random();"), - // Voisins 2 sauts (tous) - // Version optimisée de : "select end as eid, 0.1 as r1, 0.1 as r2, 0.3 as r0, 0.5 as trash from relation where start in (select end from relation where start = $centerEid and type not in ($banned_types)) and type not in ($banned_types) order by random();" - array('w'=>10, 'd'=>8, 's'=>"select x as eid, 0.1 as r1, 0.1 as r2, 0.3 as r0, 0.5 as trash from (select x from (select X.eid + Y.dumb as x from (select B.end as eid from relation as A, relation as B where A.type not in ($banned_types) and A.start = $centerEid and B.type not in ($banned_types) and B.start = A.end limit ".($cloudSize*4).") as X, (select 0 as dumb) as Y)) order by random();"), - // Centre pointe vers X, M pointe vers X aussi, on prend M. - // Version optimisée de : "select start as eid from relation where end in (select end from relation where start = $centerEid) and type not in ($banned_types) order by random();" - // Ce n'est toujours pas ça… : "select eid from (select B.start as eid from relation as A, relation as B where A.type not in ($banned_types) and A.start = $centerEid and B.type not in ($banned_types) and B.end = A.end limit 1) order by random();" - // Tordu, mais ça marche \o/ . En fait il faut empêcher l'optimiseur de ramener le random avant le limit (et l'optimiseur est malin… :) - array('w'=>10, 'd'=>8, 's'=>"select x as eid, 0.1 as r1, 0.1 as r2, 0.2 as r0, 0.6 as trash from (select x from (select X.eid + Y.dumb as x from (select B.start as eid from relation as A, relation as B where A.type not in ($banned_types) and A.start = $centerEid and B.type not in ($banned_types) and B.end = A.end limit ".($cloudSize*4).") as X, (select 0 as dumb) as Y)) order by random();"), + array('w'=>40, 'd'=>1, 's'=>sql1JumpGoodType($r1, $r2, $centerEid)), + array('w'=>40, 'd'=>2, 's'=>sql1JumpViaRAssociated0($centerEid)), + array('w'=>20, 'd'=>3.1, 's'=>sql1JumpViaOtherRelation($centerEid, $r1, $r2, $banned_types)), + array('w'=>30, 'd'=>3.2, 's'=>sql2JumpWithMixR1R2ForLinks($r1, $r2, $centerEid)), + array('w'=>20, 'd'=>5, 's'=>sql1JumpR1DivR2Plus1JumpSynonymOneHopWithType($r1, $r2, $centerEid)), + array('w'=>20, 'd'=>6, 's'=>sql1JumpR1DivR2Plus1JumpSynonym($r1, $r2, $centerEid)), + array('w'=>10, 'd'=>8, 's'=>sql2JumpAll($centerEid, $cloudSize)), + array('w'=>10, 'd'=>8, 's'=>sqlXPointsToMMPointsToXTakeM($cloudSize)), 'rand' => array('w'=>5, 'd'=>10, 's'=>false) // random. Le r1 et r2 de random sont juste en-dessous ); @@ -214,7 +199,7 @@ function cgBuildCloud($centerEid, $cloudSize, $sources, $sumWeights) $rejected = false; // Ne pas mettre le mot central dans le nuage. if ($res['eid'] == $centerEid) { continue; } - $nodeName = $db->querySingle("select name from node where eid=".$res['eid'].";"); + $nodeName = $db->querySingle(sqlGetNameFromNode($res)); if (substr($nodeName, 0, 2) == "::") { continue; } foreach ($cloud as $c) { if ($c['eid'] == $res['eid']) { @@ -300,7 +285,7 @@ function cgInsert($centerEid, $cloud, $r1, $r2, $totalDifficulty) */ function randomGameCore() { $db = getDB(); - return $db->querySingle("select gid from game where gid = (abs(random()) % (select max(gid) from game))+1 or gid = (select max(gid) from game where gid > 0) order by gid limit 1;"); + return $db->querySingle(sqlGetGidFromGame()); } /** Sélection aléatoire d'une partie de la base de données parmis les parties à jouer. @@ -318,7 +303,7 @@ function randomGame() $gid = randomGameCore(); if ($gid === null) - throw new Exception("Erreur lors de la récupération de la partie. Vérifiez qu'il y a au moins une partie.", 6); + errGetGame(); } return $gid; } @@ -335,11 +320,11 @@ function formatWord($word) { while (($pos = strpos($word, ">")) !== false) { $res .= substr($word,0,$pos) . " ("; $eid = intval(substr($word,$pos+1)); - if ($eid == 0) { throw new Exception("Erreur lors du suivi des pointeurs de spécialisation du mot $word.", 7); } - if (in_array($eid, $stack)) { throw new Exception("Boucle rencontrée lors du suivi des pointeurs de spécialisation du mot $word.", 8); } - if (count($stack) > 10) { throw new Exception("Trop de niveaux de récursions lors du suivi des pointeurs de spécialisation du mot $word.", 9); } + if ($eid == 0) { errFollowingPointer($word); } + if (in_array($eid, $stack)) { errLoopDetected($word); } + if (count($stack) > 10) { errTooMuchRecursion($word); } $stack[] = $eid; - $word = $db->querySingle("select name from node where eid = $eid"); + $word = $db->querySingle(sqlGetNameFromNodeWithEid($eid)); } $res .= $word; @@ -362,8 +347,7 @@ function game2json($user, $gameId) $db->exec("INSERT INTO played_game(pgid, gid, login, timestamp) VALUES (null, ".$gameId.", '$user', -1);"); $pgid = $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 = $db->query(sqlGetGamesForId($gameId)); $game = $game->fetchArray(); $retstr = ""; @@ -371,7 +355,7 @@ function game2json($user, $gameId) $retstr .= '"center":{"id":'.$game['eid_central_word'].',"name":'.json_encode(''.formatWord($game['name_central_word'])).'},'; $retstr .= '"cloudsize":10,"cloud":['; // TODO ! compter dynamiquement. - $res = $db->query("select eid_word,(select name from node where eid=eid_word) as name_word from game_cloud where gid = ".$gameId.";"); + $res = $db->query(sqlGetWordEidAndName($gameId)); $notfirst = false; while ($x = $res->fetchArray()) @@ -401,7 +385,7 @@ function game2array($user, $gameId) $pgid = $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 = $db->query(sqlGetGamesForId($gameId)); $game = $game->fetchArray(); $ret = array(); @@ -414,7 +398,7 @@ function game2array($user, $gameId) $ret['center'] = array('id' => $game['eid_central_word'], 'name' => formatWord($game['name_central_word'])); $ret['cloud'] = array(); // TODO ! compter dynamiquement. - $res = $db->query("select eid_word,(select name from node where eid=eid_word) as name_word, num, difficulty, totalWeight, probaR1, probaR2, probaR0, probaTrash from game_cloud where gid = ".$gameId.";"); + $res = $db->query(sqlGetInformationAboutGame($gameId)); while ($x = $res->fetchArray()) { @@ -531,11 +515,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(sqlGameIsOK($pgid, $gid, $user))) { return getGameScores($user, $pgid, $gid); } - $userReputation = computeUserReputation($db->querySingle("SELECT score FROM user WHERE login='".$user."';")); + $userReputation = computeUserReputation($db->querySingle(sqlGetScoreForUser($user))); $db->exec("begin transaction;"); $db->exec("update played_game set timestamp = ".time()." where pgid = $pgid;"); @@ -555,7 +539,7 @@ function setGame($user, $pgid, $gid, $answers) $num = intval($row['num']); $nbScores++; if (!isset($answers[$num])) { - throw new Exception("Cette requête \"Set partie\" ne donne pas de réponse (une relation) pour le mot numéro $num de la partie.", 5); + errSetPartiNoRelation($num); } $relanswer = intval($answers[$num]); @@ -565,7 +549,7 @@ function setGame($user, $pgid, $gid, $answers) case $r2: $answer = 1; $probaRx = "probaR2"; break; case $r0: $answer = 2; $probaRx = "probaR0"; break; case $trash: $answer = 3; $probaRx = "probaTrash"; break; - default: throw new Exception("Réponse ($relanswer) invalide pour le mot $num. Les réponses possibles sont : $r1, $r2, $r0, $trash", 5); + default: errAnswerInvalidForWord($r1, $r2, $r0, $trash); } $wordScore = computeScore(normalizeProbas($row), $row['difficulty'], $answer, $userReputation); @@ -587,17 +571,17 @@ function setGame($user, $pgid, $gid, $answers) function getGameScores($user, $pgid, $gid) { $db = getDB(); - $timestamp = $db->querySingle("SELECT timestamp FROM played_game WHERE pgid = $pgid and $gid = $gid and login = '$user';"); + $timestamp = $db->querySingle(sqlGetPlayedGameTime($pgid, $gid, $user)); if ($timestamp == -1) { - throw new Exception("Cette partie n'a jamais été jouée.", 4); // TODO : code d'erreur en doublon avec celui ci-dessous. + errGameNeverPlayed(); } else if ($timestamp == null) { - throw new Exception("Cette partie n'est associée à votre nom d'utilisateur.", 4); + errGameNotAssociatedWithUser(); } $gameScore = 0; $scores = array(); $nbScores = 0; - $res = $db->query("SELECT num,score from played_game_cloud where pgid = $pgid and gid = $gid;"); + $res = $db->query(sqlGetNumAndScoreFromGame($pgid, $gid)); while ($row = $res->fetchArray()) { $nbScores++; @@ -648,7 +632,7 @@ function setGameGetScore($user, $pgid, $gid, $answers) { function insertNode($node) { $db = getDB(); - if($db->querySingle("SELECT eid FROM node WHERE name='".SQLite3::escapeString($node)."'") == null) { + if($db->querySingle(sqlGetEidFromNode($node)) == null) { $db->exec("INSERT INTO node(name,type,weight) VALUES('".SQLite3::escapeString($node)."',1,50);"); return true; } @@ -664,6 +648,6 @@ function insertNode($node) { function getNodeEid($node) { $db = getDB(); - return $db->querySingle("SELECT eid FROM node WHERE name='".SQLite3::escapeString($node)."';"); + return $db->querySingle(sqlGetEidFromNode($node)); } ?> diff --git a/code/serveur/php/ressources/errors.inc b/code/serveur/php/ressources/errors.inc new file mode 100644 index 0000000..90715b6 --- /dev/null +++ b/code/serveur/php/ressources/errors.inc @@ -0,0 +1,39 @@ +function errRequestIncomplete() { + throw new Exception("La requête est incomplète", 1); +} + +function errUserUnknownOrBadPassword() { + throw new Exception("Utilisateur non enregistré ou mauvais mot de passe", 2); +} + +function errGameNeverPlayed() { + throw new Exception("Cette partie n'a jamais été jouée.", 3); // TODO : code d'erreur en doublon avec celui ci-dessous. +} + +function errGameNotAssociatedWithUser() { + throw new Exception("Cette partie n'est pas associée à votre nom d'utilisateur.", 4); +} + +function errAnswerInvalidForWord($r1, $r2, $r0, $trash) { + throw new Exception("Réponse ($relanswer) invalide pour le mot $num. Les réponses possibles sont : $r1, $r2, $r0, $trash", 5); +} + +function errSetPartiNoRelation($num) { + throw new Exception("Cette requête \"Set partie\" ne donne pas de réponse (une relation) pour le mot numéro $num de la partie.", 6); +} + +function errGetGame() { + throw new Exception("Erreur lors de la récupération de la partie. Vérifiez qu'il y a au moins une partie.", 7); +} + +function errFollowingPointer($word) { + throw new Exception("Erreur lors du suivi des pointeurs de spécialisation du mot $word.", 8); } +} + +function errLoopDetected($word) { + throw new Exception("Boucle rencontrée lors du suivi des pointeurs de spécialisation du mot $word.", 9); } +} + +function errTooMuchRecursion($word) { + throw new Exception("Trop de niveaux de récursions lors du suivi des pointeurs de spécialisation du mot $word.", 10); } +} diff --git a/code/serveur/php/ressources/sql.inc b/code/serveur/php/ressources/sql.inc new file mode 100644 index 0000000..f93a00c --- /dev/null +++ b/code/serveur/php/ressources/sql.inc @@ -0,0 +1,119 @@ +$typer1r2 = "type in ($r1, $r2)"; +$banned_types = "4, 12, 36, 18, 29, 45, 46, 47, 48, 1000, 1001"; + +function sqlGetPassword($user) { + return "SELECT hash_passwd FROM user WHERE login='".$user."';"; +} + +function sqlGetEIDCenterNode() { + return "select eid from random_center_node where rowid = (abs(random()) % (select max(rowid) from random_center_node))+1;"; +} + +function sqlGetEIRCloudNode() { + return "select eid from random_cloud_node where rowid = (abs(random()) % (select max(rowid) from random_cloud_node))+1;"; +} + +// Voisins 1 saut du bon type (= relations déjà existantes) +function sql1JumpGoodType($r1, $r2, $centerEid) { + global $typer1r2; + + return "select end as eid, type = $r1 as r1, type = $r2 as r2, 0 as r0, 0 as trash from relation where start = $centerEid and $typer1r2 order by random();"; +} + +// Voisins 1 saut via r_associated (0), donc qu'on voudrait spécifier si possible. +function sql1JumpViaRAssociated0($centerEid) { + return "select end as eid, 0.25 as r1, 0.25 as r2, 0.5 as r0, 0 as trash from relation where start = $centerEid and type = 0 order by random();"; +} + +// Voisins 1 saut via les autres relations +function sql1JumpViaOtherRelation($centerEid, $r1, $r2) { + global $banned_types; + + return "select end as eid, 0.1 as r1, 0.1 as r2, 0.8 as r0, 0 as trash from relation where start = $centerEid and type not in (0, $r1, $r2, $banned_types) order by random();"; +} + +// Voisins 2 sauts, avec un mix de R1 et R2 pour les liens. Par ex [ A -R1-> B -R2-> C ] ou bien [ A -R2-> B -R2-> C ] +// Version optimisée de : "select end as eid from relation where $typer1r2 and start in oneHopWithType order by random();" +function sql2JumpWithMixR1R2ForLinks($r1, $r2, $centerEid) { + global $typer1r2; + + return "select B.end as eid, ((A.type = $r1) + (B.type = $r1)) / 3. as r1, ((A.type = $r2) + (B.type = $r2)) / 3. as r2, 1/6. as r0, 1/6. as trash from relation as A, relation as B where A.start = $centerEid and A.$typer1r2 and B.start = A.end and B.$typer1r2 order by random();"; +} + +// Voisins 1 saut r1/r2 + 1 saut synonyme +// Version optimisée de : "select end as eid from relation where start in oneHopWithType and type = 5 order by random()"; +function sql1JumpR1DivR2Plus1JumpSynonymOneHopWithType($r1, $r2, $centerEid) { + global $typer1r2; + + return "select B.end as eid, (A.type = $r1) * 0.75 as r1, (A.type = $r2) * 0.75 as r2, 0.25 as r0, 0 as trash from relation as A, relation as B where A.start = $centerEid and A.$typer1r2 and B.start = A.end and B.type = 5 order by random();"; +} + +// Version optimisée de : "select end as eid from relation where start in (select end from relation where start = $centerEid and type = 5) and $typer1r2 order by random();" +function sql1JumpR1DivR2Plus1JumpSynonym($r1, $r2, $centerEid) { + global $typer1r2; + + return "select B.end as eid, (B.type = $r1) * 0.75 as r1, (B.type = $r2) * 0.75 as r2, 0.25 as r0, 0 as trash from relation as A, relation as B where A.start = $centerEid and A.type = 5 and B.start = A.end and B.$typer1r2 order by random();"; +} + +// Voisins 2 sauts (tous) +// Version optimisée de : "select end as eid, 0.1 as r1, 0.1 as r2, 0.3 as r0, 0.5 as trash from relation where start in (select end from relation where start = $centerEid and type not in ($banned_types)) and type not in ($banned_types) order by random();" +function sql2JumpAll($centerEid, $cloudSize) { + global $banned_types; + + return "select x as eid, 0.1 as r1, 0.1 as r2, 0.3 as r0, 0.5 as trash from (select x from (select X.eid + Y.dumb as x from (select B.end as eid from relation as A, relation as B where A.type not in ($banned_types) and A.start = $centerEid and B.type not in ($banned_types) and B.start = A.end limit ".($cloudSize*4).") as X, (select 0 as dumb) as Y)) order by random();"; +} + +// Centre pointe vers X, M pointe vers X aussi, on prend M. +// Version optimisée de : "select start as eid from relation where end in (select end from relation where start = $centerEid) and type not in ($banned_types) order by random();" +// Ce n'est toujours pas ça… : "select eid from (select B.start as eid from relation as A, relation as B where A.type not in ($banned_types) and A.start = $centerEid and B.type not in ($banned_types) and B.end = A.end limit 1) order by random();" +// Tordu, mais ça marche \o/ . En fait il faut empêcher l'optimiseur de ramener le random avant le limit (et l'optimiseur est malin… :) +function sqlXPointsToMMPointsToXTakeM($cloudSize) { + global $banned_types; + + return "select x as eid, 0.1 as r1, 0.1 as r2, 0.2 as r0, 0.6 as trash from (select x from (select X.eid + Y.dumb as x from (select B.start as eid from relation as A, relation as B where A.type not in ($banned_types) and A.start = $centerEid and B.type not in ($banned_types) and B.end = A.end limit ".($cloudSize*4).") as X, (select 0 as dumb) as Y)) order by random();"; +} + +function sqlGetNameFromNode($res) { + return "select name from node where eid=".$res['eid'].";"; +} + +function sqlGetGidFromGame() { + return "select gid from game where gid = (abs(random()) % (select max(gid) from game))+1 or gid = (select max(gid) from game where gid > 0) order by gid limit 1;"; +} + +function sqlGetNameFromNodeWithEid($eid) { + return "select name from node where eid = $eid"; +} + +// TODO Yoann : faire des tests d'erreur pour ces select ? +function sqlGetGamesForId($gameId) { + return "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.";"; +} + +function sqlGetWordEidAndName($gameId) { + return "select eid_word,(select name from node where eid=eid_word) as name_word from game_cloud where gid = ".$gameId.";"; +} + +function sqlGetInformationAboutGame($gameId) { + return "select eid_word,(select name from node where eid=eid_word) as name_word, num, difficulty, totalWeight, probaR1, probaR2, probaR0, probaTrash from game_cloud where gid = ".$gameId.";"; +} + +function sqlGameIsOK($pgid, $gid, $user) { + return "SELECT 'ok' FROM played_game WHERE pgid = $pgid and $gid = $gid and login = '$user' and timestamp = -1;"; +} + +function sqlGetScoreForUser($user) { + return "SELECT score FROM user WHERE login='".$user."';"; +} + +function sqlGetPlayedGameTime($pgid, $gid, $user) { + return "SELECT timestamp FROM played_game WHERE pgid = $pgid and $gid = $gid and login = '$user';"; +} + +function sqlGetNumAndScoreFromGame($pgid, $gid) { + return "SELECT num,score from played_game_cloud where pgid = $pgid and gid = $gid;"; +} + +function sqlGetEidFromNode($node) { + return "SELECT eid FROM node WHERE name='".SQLite3::escapeString($node)."'"; +} \ No newline at end of file diff --git a/code/serveur/php/server.php b/code/serveur/php/server.php index b248b78..3dcdc83 100644 --- a/code/serveur/php/server.php +++ b/code/serveur/php/server.php @@ -31,7 +31,7 @@ function logError($errNum, $msg, $other="") function main() { if(!isset($_GET['action']) || !isset($_GET['user']) || !isset($_GET['passwd'])) { - throw new Exception("La requête est incomplète", 2); + errRequestIncomplete(); } // Login @@ -39,7 +39,7 @@ function main() $user = SQLite3::escapeString($_GET['user']); $loginIsOk = checkLogin($user, $_GET['passwd']); if ($action != 3 && (!$loginIsOk)) { - throw new Exception("Utilisateur non enregistré ou mauvais mot de passe", 3); + errUserUnknownOrBadPassword(); } if ($action == 3) { echo '{"login_ok":' . ($loginIsOk ? 'true' : 'false') . '}'; @@ -53,26 +53,26 @@ function main() if ($action == 2) { // "Create partie" // Requête POST : http://serveur/server.php?action=2&nb=2&mode=normal&user=foo&passwd=bar if (!isset($_GET['nb']) || !isset($_GET['mode'])) { - throw new Exception("La requête est incomplète", 2); + errRequestIncomplete(); } createGame(intval($_GET['nb']), $_GET['mode']); echo '{"success":1}'; } else if($action == 0) { // "Get partie" // Requête POST : http://serveur/server.php?action=0&nb=2&mode=normal&user=foo&passwd=bar if(!isset($_GET['nb']) || !isset($_GET['mode'])) { - throw new Exception("La requête est incomplète", 2); + errRequestIncomplete(); } getGame($user, intval($_GET['nb']), $_GET['mode']); } 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 if (!isset($_GET['pgid']) || !isset($_GET['gid'])) { - throw new Exception("La requête est incomplète", 2); + errRequestIncomplete(); } // TODO : il faudrait filtrer les paramètres qui correspondent à une réponse // au lieu d'envoyer $_GET en entier, mais on ne connaît pas leur nom à l'avance. setGameGetScore($user, $_GET['pgid'], $_GET['gid'], $_GET); } else { - throw new Exception("Commande inconnue", 2); + errRequestIncomplete(); } } From 436c3f1886b859f333454e23211d99b409b77bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Thu, 7 Apr 2011 10:20:13 +0200 Subject: [PATCH 13/20] Refactorisation, encore et toujours. --- code/html5/my-extensions.js | 22 +++++++++++++++++++--- code/html5/pticlic.js | 28 +++++++--------------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/code/html5/my-extensions.js b/code/html5/my-extensions.js index abd2101..bbdd278 100644 --- a/code/html5/my-extensions.js +++ b/code/html5/my-extensions.js @@ -1,9 +1,10 @@ $.fn.fitFont = function(w, h, minFont, maxFont) { minFont = minFont || 0; maxFont = maxFont || Infinity; - e = $(this) + e = $(this); var oldpos = e.css("position"); e.css("position", "absolute"); + // TODO : reset temporairement le max-width. var size = parseInt(e.css("font-size"), 10); var i = 0; @@ -34,6 +35,21 @@ $.fn.fitFont = function(w, h, minFont, maxFont) { return e; } +$.fn.fitIn = function(e, t, r, b, l) { + e = $(e); + if (isNaN(+t)) t = 0; + if (isNaN(+r)) r = t; + if (isNaN(+b)) b = t; + if (isNaN(+l)) l = r; + var w = e.width(); + var h = e.height(); + t *= h; + r *= w; + b *= h; + l *= w; + $(this).fitFont(w - r - l, h - t - b, 20).center(e.center()); +} + function queueize(method) { return function() { var that = $(this); @@ -54,8 +70,8 @@ $.fn.wh = function(w, h) { $.fn.relativePos = function(xAnchor, yAnchor, to) { var that = $(this); - var deltaX = that.width() * xAnchor; - var deltaY = that.height() * yAnchor; + var deltaX = that.outerWidth() * xAnchor; + var deltaY = that.outerHeight() * yAnchor; if (to) { that.css("position", "absolute"); diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index d6c2e44..dcbaaca 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -2,7 +2,7 @@ function jss() { var w=480, h=800; var mch = h/8, mnh = h*0.075; - $("body") + $("body, html") .css({ padding: 0, margin: 0, @@ -18,30 +18,16 @@ function jss() { .north($("#screen").north()); $("#mc-caption") - .css({ - maxWidth: w*0.9, - textAlign: "center" - }) - .fitFont(w*0.9, mch*0.9, 20) - .center($("#mc-caption-block").center()); + .fitIn("#mc-caption-block", 0.1); $("#mn-caption-block") - .css({ - borderWidth: h/100, - position: "absolute" - }) + .css({borderWidth: h/100}) .wh(w, mnh) .north($("#mc-caption-block").south()); $("#mn-caption") - .css({ - maxWidth: w*0.9, - textAlign: "center", - position: "absolute", - zIndex: 10 - }) - .fitFont(w*0.9, mnh*0.9, 20) - .center($("#mn-caption-block").center()); + .css({zIndex: 10}) + .fitIn("#mn-caption-block"); $(".relations > div") .css({ @@ -71,8 +57,8 @@ function jss() { function animateNext(e, button) { console.log(e, e.clientX, e.clientY); - $(button).qAddClass("hot").delay(100).qRemoveClass("hot"); - $("#mn-caption").animate({left:e.clientX, top:e.clientY},1500); + $(button).clearQueue().qAddClass("hot").delay(100).qRemoveClass("hot"); + $("#mn-caption").clearQueue().animate({left:e.clientX, top:e.clientY},1500); } From 04d444af24aeb694fdd612cb633b526ff4bd77ca Mon Sep 17 00:00:00 2001 From: Bertrand BRUN Date: Thu, 7 Apr 2011 11:49:20 +0200 Subject: [PATCH 14/20] Ajout de l'animation --- code/html5/index.html | 17 +++++---- code/html5/pticlic.js | 86 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/code/html5/index.html b/code/html5/index.html index dc2a777..9c56c5e 100644 --- a/code/html5/index.html +++ b/code/html5/index.html @@ -26,20 +26,15 @@ body { border-bottom: medium solid #44AA44; background-color: #F0F8D0; } -.relations div { + +.relation { background-color: #F0F8D0; border: thin solid #44AA44; -moz-border-radius: 10px; + -webkit-border-radius: 10px; background-repeat: no-repeat; } -.relations .rid-1 { background-image: url("img/rel/-1.png"); } -.relations .rid0 { background-image: url("img/rel/0.png"); } -.relations .rid5 { background-image: url("img/rel/5.png"); } -.relations .rid7 { background-image: url("img/rel/7.png"); } -.relations .rid9 { background-image: url("img/rel/9.png"); } -.relations .rid10 { background-image: url("img/rel/10.png"); } - .relations .hot { background-color: yellow; } @@ -56,6 +51,12 @@ body {
+
diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index dcbaaca..873e5e1 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -29,28 +29,65 @@ function jss() { .css({zIndex: 10}) .fitIn("#mn-caption-block"); - $(".relations > div") - .css({ - margin: 10, - height: 72, - padding: 10, - }); - // TODO : fitFont pour ".relations div" - $(".relations > div:nth-child(odd)") +/* $(".relations > .relation:nth-child(odd)") .css({ backgroundPosition: "2% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. textAlign: "right", - paddingLeft: 76 - }); + }) + .find(".icon").css("float", "left"); - $(".relations > div:nth-child(even)") + $(".relations > .relation:nth-child(even)") .css({ backgroundPosition: "98% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. textAlign: "left", - paddingRight: 76 + }) + .find(".icon").css("float", "right"); */ + + $(".relation > *") + .css({ + display: "inline-block", + position: "absolute", + textAlign: "right" }); + $(".relation") + .height(76) + .width(w); + + // TODO : fitFont pour ".relations div" + /* $(".relations > .relation:nth-child(odd)") + .css({ + backgroundPosition: "2% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. + textAlign: "right", + }) + .find(".icon").css("float", "left"); + + $(".relations > .relation:nth-child(even)") + .css({ + backgroundPosition: "98% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. + textAlign: "left", + }) + .find(".icon").css("float", "right"); */ + + $(".relation > *") + .css({ + display: "inline-block", + position: "absolute" + }); + + $(".relation") + .height(76) + .width(w); + + $(".relation").each(function (i,e) { + e = $(e); + e.find(".icon") + .west(e.west()); + e.find(".text") + .east(e.east()); + }); + $(".relations") .south($("#screen").south()); } @@ -58,7 +95,19 @@ function jss() { function animateNext(e, button) { console.log(e, e.clientX, e.clientY); $(button).clearQueue().qAddClass("hot").delay(100).qRemoveClass("hot"); - $("#mn-caption").clearQueue().animate({left:e.clientX, top:e.clientY},1500); + var el = $("#mn-caption") + .clone() + .removeClass("mn") + .appendTo("#screen") + .clearQueue(); + var oldOff = el.offset(); + el.offset({left:e.pageX, top:e.pageY}); + var pos = el.position(); + el.offset(oldOff); + pos.fontSize = 0; + el.animate(pos,500).queue(function() { + el.remove(); + }); } @@ -81,9 +130,14 @@ $(function () { } $.each(game.cat, function(i, cat) { - $('
') - .html(cat.name.replace(/%(m[cn])/g, '')) - .addClass("rid"+cat.id) + $('#templates .relation') + .clone() + .find(".text") + .html(cat.name.replace(/%(m[cn])/g, '')) + .end() + .find(".icon") + .attr("src", "img/rel/"+cat.id+".png") + .end() .click(function(e) { answers[currentWordNb++] = cat.id; animateNext(e, this); From 2b9af4deea3c28fe61aaed9165ff6cb36d9f3e59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Thu, 7 Apr 2011 14:05:32 +0200 Subject: [PATCH 15/20] =?UTF-8?q?Un=20peu=20de=20nettoyage=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/html5/jquery-ui-1.8.11.custom.min.js | 65 +++++++++++++++++++---- code/html5/my-extensions.js | 49 ++++++++--------- code/html5/pticlic.js | 48 ++--------------- 3 files changed, 83 insertions(+), 79 deletions(-) diff --git a/code/html5/jquery-ui-1.8.11.custom.min.js b/code/html5/jquery-ui-1.8.11.custom.min.js index 0251a19..b6cc2e2 100644 --- a/code/html5/jquery-ui-1.8.11.custom.min.js +++ b/code/html5/jquery-ui-1.8.11.custom.min.js @@ -1,17 +1,62 @@ -/* - * jQuery UI Position 1.8.11 +/*! + * jQuery UI 1.8.11 * * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) * Dual licensed under the MIT or GPL Version 2 licenses. * http://jquery.org/license * - * http://docs.jquery.com/UI/Position + * http://docs.jquery.com/UI */ -(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY, -left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+= -k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-= -m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left= -d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+= -a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b), -g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); +(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.11",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106, +NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this, +"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position"); +if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f, +"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h, +d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}}); +c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a
").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent", +border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c); +return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments); +else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c), +b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",swing:function(c,a,b,d,e){return f.easing[f.easing.def](c,a,b,d,e)},easeInQuad:function(c,a,b,d,e){return d*(a/=e)*a+b},easeOutQuad:function(c,a,b,d,e){return-d*(a/=e)*(a-2)+b},easeInOutQuad:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a+b;return-d/2*(--a*(a-2)-1)+b},easeInCubic:function(c,a,b,d,e){return d*(a/=e)*a*a+b},easeOutCubic:function(c, +a,b,d,e){return d*((a=a/e-1)*a*a+1)+b},easeInOutCubic:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a+b;return d/2*((a-=2)*a*a+2)+b},easeInQuart:function(c,a,b,d,e){return d*(a/=e)*a*a*a+b},easeOutQuart:function(c,a,b,d,e){return-d*((a=a/e-1)*a*a*a-1)+b},easeInOutQuart:function(c,a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a+b;return-d/2*((a-=2)*a*a*a-2)+b},easeInQuint:function(c,a,b,d,e){return d*(a/=e)*a*a*a*a+b},easeOutQuint:function(c,a,b,d,e){return d*((a=a/e-1)*a*a*a*a+1)+b},easeInOutQuint:function(c, +a,b,d,e){if((a/=e/2)<1)return d/2*a*a*a*a*a+b;return d/2*((a-=2)*a*a*a*a+2)+b},easeInSine:function(c,a,b,d,e){return-d*Math.cos(a/e*(Math.PI/2))+d+b},easeOutSine:function(c,a,b,d,e){return d*Math.sin(a/e*(Math.PI/2))+b},easeInOutSine:function(c,a,b,d,e){return-d/2*(Math.cos(Math.PI*a/e)-1)+b},easeInExpo:function(c,a,b,d,e){return a==0?b:d*Math.pow(2,10*(a/e-1))+b},easeOutExpo:function(c,a,b,d,e){return a==e?b+d:d*(-Math.pow(2,-10*a/e)+1)+b},easeInOutExpo:function(c,a,b,d,e){if(a==0)return b;if(a== +e)return b+d;if((a/=e/2)<1)return d/2*Math.pow(2,10*(a-1))+b;return d/2*(-Math.pow(2,-10*--a)+2)+b},easeInCirc:function(c,a,b,d,e){return-d*(Math.sqrt(1-(a/=e)*a)-1)+b},easeOutCirc:function(c,a,b,d,e){return d*Math.sqrt(1-(a=a/e-1)*a)+b},easeInOutCirc:function(c,a,b,d,e){if((a/=e/2)<1)return-d/2*(Math.sqrt(1-a*a)-1)+b;return d/2*(Math.sqrt(1-(a-=2)*a)+1)+b},easeInElastic:function(c,a,b,d,e){c=1.70158;var g=0,h=d;if(a==0)return b;if((a/=e)==1)return b+d;g||(g=e*0.3);if(h w || e.height() > h) --size; + if (this.width() > w || this.height() > h) --size; if (size < minFont) size = minFont; if (size > maxFont) size = maxFont; - e.css("font-size", size); + this.css("font-size", size); - e.css("position", oldpos); - return e; + this.css("position", oldpos); + return this; } $.fn.fitIn = function(e, t, r, b, l) { @@ -47,15 +46,14 @@ $.fn.fitIn = function(e, t, r, b, l) { r *= w; b *= h; l *= w; - $(this).fitFont(w - r - l, h - t - b, 20).center(e.center()); + this.fitFont(w - r - l, h - t - b, 20).center(e.center()); } function queueize(method) { return function() { - var that = $(this); - var args = arguments; - return that.queue(function(next) { - that[method].apply(that,args); + var $this = this; + return this.queue(function(next) { + $this[method].apply($this,arguments); next(); }); }; @@ -65,23 +63,22 @@ $.fn.qAddClass = queueize("addClass"); $.fn.qRemoveClass = queueize("removeClass"); $.fn.wh = function(w, h) { - return $(this).width(w).height(h); + return this.width(w).height(h); } $.fn.relativePos = function(xAnchor, yAnchor, to) { - var that = $(this); - var deltaX = that.outerWidth() * xAnchor; - var deltaY = that.outerHeight() * yAnchor; + var deltaX = this.outerWidth() * xAnchor; + var deltaY = this.outerHeight() * yAnchor; if (to) { - that.css("position", "absolute"); - that.offset({ + this.css("position", "absolute"); + this.offset({ left: to.left - deltaX, top: to.top - deltaY }); - return that; + return this; } else { - var pos = that.offset(); + var pos = this.offset(); pos.left += deltaX; pos.top += deltaY; return pos; @@ -101,5 +98,5 @@ $.each({ }, function(i,e) { var x = e.x; var y = e.y; - $.fn[i] = function(to) { return $(this).relativePos(x, y, to); }; + $.fn[i] = function(to) { return this.relativePos(x, y, to); }; }); diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index 873e5e1..14cf744 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -29,56 +29,18 @@ function jss() { .css({zIndex: 10}) .fitIn("#mn-caption-block"); - // TODO : fitFont pour ".relations div" -/* $(".relations > .relation:nth-child(odd)") - .css({ - backgroundPosition: "2% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. - textAlign: "right", - }) - .find(".icon").css("float", "left"); - - $(".relations > .relation:nth-child(even)") - .css({ - backgroundPosition: "98% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. - textAlign: "left", - }) - .find(".icon").css("float", "right"); */ - $(".relation > *") .css({ display: "inline-block", position: "absolute", textAlign: "right" }); - + + $(".relation .icon") + .wh(72,72); + $(".relation") - .height(76) - .width(w); - - // TODO : fitFont pour ".relations div" - /* $(".relations > .relation:nth-child(odd)") - .css({ - backgroundPosition: "2% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. - textAlign: "right", - }) - .find(".icon").css("float", "left"); - - $(".relations > .relation:nth-child(even)") - .css({ - backgroundPosition: "98% center", // TODO : virer le pourcentage, et séparer l'icône dans un nouvel élément. - textAlign: "left", - }) - .find(".icon").css("float", "right"); */ - - $(".relation > *") - .css({ - display: "inline-block", - position: "absolute" - }); - - $(".relation") - .height(76) - .width(w); + .wh(w,76); $(".relation").each(function (i,e) { e = $(e); From a2cb9dd345300d5fdd73ffffe9c54001606434c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Thu, 7 Apr 2011 14:48:11 +0200 Subject: [PATCH 16/20] =?UTF-8?q?Animation=20pour=20l'apparition=20du=20mo?= =?UTF-8?q?t=20central,=20nettoyage=20des=20animations=20termin=C3=A9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/html5/my-extensions.js | 10 ++++----- code/html5/pticlic.js | 45 ++++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/code/html5/my-extensions.js b/code/html5/my-extensions.js index f5027fc..f229b60 100644 --- a/code/html5/my-extensions.js +++ b/code/html5/my-extensions.js @@ -66,17 +66,17 @@ $.fn.wh = function(w, h) { return this.width(w).height(h); } -$.fn.relativePos = function(xAnchor, yAnchor, to) { +$.fn.relativePos = function(xAnchor, yAnchor, to, justCss) { var deltaX = this.outerWidth() * xAnchor; var deltaY = this.outerHeight() * yAnchor; if (to) { this.css("position", "absolute"); - this.offset({ + var css = { left: to.left - deltaX, top: to.top - deltaY - }); - return this; + }; + return (justCss ? css : this.offset(css)); } else { var pos = this.offset(); pos.left += deltaX; @@ -98,5 +98,5 @@ $.each({ }, function(i,e) { var x = e.x; var y = e.y; - $.fn[i] = function(to) { return this.relativePos(x, y, to); }; + $.fn[i] = function(to, justCss) { return this.relativePos(x, y, to, justCss); }; }); diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index 14cf744..be9a5dd 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -54,25 +54,6 @@ function jss() { .south($("#screen").south()); } -function animateNext(e, button) { - console.log(e, e.clientX, e.clientY); - $(button).clearQueue().qAddClass("hot").delay(100).qRemoveClass("hot"); - var el = $("#mn-caption") - .clone() - .removeClass("mn") - .appendTo("#screen") - .clearQueue(); - var oldOff = el.offset(); - el.offset({left:e.pageX, top:e.pageY}); - var pos = el.position(); - el.offset(oldOff); - pos.fontSize = 0; - el.animate(pos,500).queue(function() { - el.remove(); - }); -} - - $(function () { var url = "tmp.json"; $.getJSON(url, function(data) { @@ -91,6 +72,31 @@ $(function () { jss(); } + function animateNext(e, button) { + var duration = 700; + + var mn = $("#mn-caption"); + + $(button).addClass("hot").removeClass("hot", duration); + + (mn) + .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()) + .clearQueue() + .animate({left:e.pageX, top:e.pageY, fontSize: 0}, duration) + .queue(function() { $(this).remove(); }); + + refresh(); + var fs = mn.css("fontSize"); + var mncbCenter = $("#mn-caption-block").center(); + + (mn) + .css("fontSize", 0) + .animate({fontSize: fs}, {duration:duration, step:function(){mn.center(mncbCenter);}}); + } + $.each(game.cat, function(i, cat) { $('#templates .relation') .clone() @@ -103,7 +109,6 @@ $(function () { .click(function(e) { answers[currentWordNb++] = cat.id; animateNext(e, this); - refresh(); }) .appendTo(".relations"); }); From cfe1023c11f8918e0fdcb46717d98c1719ba61e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Sun, 10 Apr 2011 00:29:36 +0200 Subject: [PATCH 17/20] =?UTF-8?q?Correction=20de=20quelques=20bugs=20dans?= =?UTF-8?q?=20l'algo=20de=20dichotomie,=20nettoyage,=20while=20(true)=20{?= =?UTF-8?q?=20lisibilit=C3=A9++;=20lisibilit=C3=A9--;=20}?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/html5/img/rel/default.png | Bin 0 -> 3852 bytes code/html5/index.html | 16 +++---- code/html5/my-extensions.js | 69 ++++++++++++++++------------ code/html5/pticlic.js | 81 ++++++++++++++++++--------------- code/html5/tmp.json | 2 +- 5 files changed, 94 insertions(+), 74 deletions(-) create mode 100644 code/html5/img/rel/default.png diff --git a/code/html5/img/rel/default.png b/code/html5/img/rel/default.png new file mode 100644 index 0000000000000000000000000000000000000000..d3f183897bf2366601df42630725859f517f07a3 GIT binary patch literal 3852 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 @@ -52,9 +52,9 @@ body {
diff --git a/code/html5/my-extensions.js b/code/html5/my-extensions.js index f229b60..7e75cee 100644 --- a/code/html5/my-extensions.js +++ b/code/html5/my-extensions.js @@ -1,36 +1,47 @@ +Number.prototype.clip = function(min, max) { + return Math.min(Math.max(this, min), max); +}; + +function dichotomy(start, isBigger) { + 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; + else max = half; + } + while (half > 1 && isBigger(half)) { --half; } + return half; +} + +$.fn.maxWidth = function() { + max = 0; + this.each(function(i,e){ max = Math.max(max, $(e).width()); }); + return max; +} +$.fn.maxHeight = function() { + max = 0; + this.each(function(i,e){ max = Math.max(max, $(e).height()); }); + return max; +} + $.fn.fitFont = function(w, h, minFont, maxFont) { - minFont = minFont || 0; - maxFont = maxFont || Infinity; var oldpos = this.css("position"); - this.css("position", "absolute"); - // TODO : reset temporairement le max-width. - var size = parseInt(this.css("font-size"), 10); + this.css({ + position: "absolute", + maxWidth: w + }); + var wrappers = this.wrapInner("").children(); - var i = 0; - while ((this.width() < w || this.height() < h) && ++i < 10) { - size *= 2; - this.css("font-size", size); - } - - var max = size; - var min = 0; - i=0; - while (min < max && ++i < 10) { - size = (max + min) / 2; - this.css("font-size", size); - if (this.width() < w && this.height() < h) { - min = size; - } else { - max = size; - } - } - - if (this.width() > w || this.height() > h) --size; - if (size < minFont) size = minFont; - if (size > maxFont) size = maxFont; - this.css("font-size", size); + var that = this; + this.css("font-size", dichotomy(parseInt(this.css("font-size"), 10), function(x) { + that.css("fontSize", x); + return (wrappers.maxHeight() > h || wrappers.maxWidth() > w); + }).clip(minFont || 0, maxFont || Infinity)); + // Restore stuff this.css("position", oldpos); + wrappers.children().unwrap(); return this; } @@ -67,11 +78,11 @@ $.fn.wh = function(w, h) { } $.fn.relativePos = function(xAnchor, yAnchor, to, justCss) { + if (to) this.css("position", "absolute"); var deltaX = this.outerWidth() * xAnchor; var deltaY = this.outerHeight() * yAnchor; if (to) { - this.css("position", "absolute"); var css = { left: to.left - deltaX, top: to.top - deltaY diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index be9a5dd..e02f6e4 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -1,17 +1,22 @@ function jss() { - var w=480, h=800; + var w, h; + //w = 480; h=800; + w = $(window).width(); + h = $(window).height(); + var mch = h/8, mnh = h*0.075; $("body, html") .css({ padding: 0, margin: 0, + overflow: "hidden", textAlign: "left" }); $("#screen") .wh(w, h) - .north($("body").north()); // TODO : par rapport à la fenêtre entière.0 + .north($("body").north()); // TODO : par rapport à la fenêtre entière. $("#mc-caption-block") .wh(w, mch) @@ -28,27 +33,26 @@ function jss() { $("#mn-caption") .css({zIndex: 10}) .fitIn("#mn-caption-block"); - - $(".relation > *") + + $(".relationBox:visible") .css({ - display: "inline-block", - position: "absolute", - textAlign: "right" + margin: 10, + padding: 10, + MozBorderRadius: 10, + WebkitBorderRadius: 10 }); + + $(".relationBox:visible .icon") + .wh(72,72) + .css({ + float: "left", + marginRight: $(".relationBox").css("padding-left") + }); + + $(".relations") + .width(w); - $(".relation .icon") - .wh(72,72); - - $(".relation") - .wh(w,76); - - $(".relation").each(function (i,e) { - e = $(e); - e.find(".icon") - .west(e.west()); - e.find(".text") - .east(e.east()); - }); + $(".relation:visible").fitFont($(".relationBox:visible").width(), 72, 10); $(".relations") .south($("#screen").south()); @@ -61,18 +65,23 @@ $(function () { var currentWordNb = 0; var answers = []; - var refresh = function() { + var updateText = function() { + $(".mn").text(game.cloud[currentWordNb].name); + $(".mc").text(game.center.name); + jss(); + } + + var nextWord = function(click, button) { + answers[currentWordNb++] = $(button).data("rid"); if (currentWordNb < game.cloud.length) { - $(".mn").text(game.cloud[currentWordNb].name); - $(".mc").text(game.center.name); + animateNext(click, button); } else { $(".relations").empty(); alert("Partie terminée !"); } - jss(); } - function animateNext(e, button) { + function animateNext(click, button) { var duration = 700; var mn = $("#mn-caption"); @@ -80,15 +89,16 @@ $(function () { $(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()) - .clearQueue() - .animate({left:e.pageX, top:e.pageY, fontSize: 0}, duration) + .animate({left:click.left, top:click.top, fontSize: 0}, duration) .queue(function() { $(this).remove(); }); - refresh(); + updateText(); var fs = mn.css("fontSize"); var mncbCenter = $("#mn-caption-block").center(); @@ -97,24 +107,23 @@ $(function () { .animate({fontSize: fs}, {duration:duration, step:function(){mn.center(mncbCenter);}}); } - $.each(game.cat, function(i, cat) { - $('#templates .relation') + $.each(game.relations, function(i, relation) { + $('#templates .relationBox') .clone() + .data("rid", relation.id) .find(".text") - .html(cat.name.replace(/%(m[cn])/g, '')) + .html(relation.name.replace(/%(m[cn])/g, '')) .end() .find(".icon") - .attr("src", "img/rel/"+cat.id+".png") + .attr("src", "img/rel/"+relation.id+".png") .end() .click(function(e) { - answers[currentWordNb++] = cat.id; - animateNext(e, this); + nextWord({left:e.pageX, top:e.pageY}, this); }) .appendTo(".relations"); }); $(window).resize(jss); - refresh(); - refresh(); // TODO : fix the bug with the margin on ".relation > div" + updateText(); }); }); diff --git a/code/html5/tmp.json b/code/html5/tmp.json index 15de993..84a661b 100644 --- a/code/html5/tmp.json +++ b/code/html5/tmp.json @@ -1 +1 @@ -[{"gid":22,"pgid":512,"cat":[{"id":10,"name":"%mc fait partie de %mn"},{"id":9,"name":"%mn est une partie de %mc"},{"id":0,"name":"%mc est en rapport avec %mn"},{"id":-1,"name":"%mn n'est pas lié à %mc"}],"center":{"id":28282,"name":"transbahuter"},"cloudsize":10,"cloud":[{"id":84632,"name":"camion"},{"id":61939,"name":"transbahutage"},{"id":104263,"name":"trimbaler"},{"id":44654,"name":"transporter"},{"id":38285,"name":"d\u00e9m\u00e9nageur"},{"id":43404,"name":"porter"},{"id":63192,"name":"transports"},{"id":130473,"name":"enthousiasmer"},{"id":90461,"name":"se trimbaler"},{"id":134609,"name":"baguenauder"}]}] \ No newline at end of file +[{"gid":22,"pgid":512,"relations":[{"id":10,"name":"%mc fait partie de %mn"},{"id":9,"name":"%mn est une partie de %mc"},{"id":0,"name":"%mc est en rapport avec %mn"},{"id":-1,"name":"%mn n'est pas lié à %mc"}],"center":{"id":28282,"name":"transbahuter"},"cloudsize":10,"cloud":[{"id":84632,"name":"camion"},{"id":61939,"name":"transbahutage"},{"id":104263,"name":"trimbaler"},{"id":44654,"name":"transporter"},{"id":38285,"name":"d\u00e9m\u00e9nageur"},{"id":43404,"name":"porter"},{"id":63192,"name":"transports"},{"id":130473,"name":"enthousiasmer"},{"id":90461,"name":"se trimbaler"},{"id":134609,"name":"baguenauder"}]}] \ No newline at end of file From 68a927d6bd99091d064e4f981010de0ea9f0e240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Sun, 10 Apr 2011 11:00:12 +0200 Subject: [PATCH 18/20] =?UTF-8?q?D=C3=A9but=20de=20la=20page=20de=20scores?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/html5/score.html | 31 +++++++++++++++++++++++++++++++ code/html5/score.json | 1 + code/html5/scores.js | 13 +++++++++++++ 3 files changed, 45 insertions(+) create mode 100644 code/html5/score.html create mode 100644 code/html5/score.json create mode 100644 code/html5/scores.js diff --git a/code/html5/score.html b/code/html5/score.html new file mode 100644 index 0000000..53d1783 --- /dev/null +++ b/code/html5/score.html @@ -0,0 +1,31 @@ + + + + PtiClic pre-alpha 0.2 + + + + + + + + +
+

Score total :

+
+ +
+ + diff --git a/code/html5/score.json b/code/html5/score.json new file mode 100644 index 0000000..5f461a5 --- /dev/null +++ b/code/html5/score.json @@ -0,0 +1 @@ +[{"id":84632,"name":"camion","score":3},{"id":61939,"name":"transbahutage","score":10},{"id":104263,"name":"trimbaler","score":4},{"id":44654,"name":"transporter","score":-2},{"id":38285,"name":"d\u00e9m\u00e9nageur","score":5},{"id":43404,"name":"porter","score":5},{"id":63192,"name":"transports","score":-1},{"id":130473,"name":"enthousiasmer","score":0},{"id":90461,"name":"se trimbaler","score":6},{"id":134609,"name":"baguenauder","score":9}] \ No newline at end of file diff --git a/code/html5/scores.js b/code/html5/scores.js new file mode 100644 index 0000000..9adbc3b --- /dev/null +++ b/code/html5/scores.js @@ -0,0 +1,13 @@ +$(function () { + var url = "score.json"; + $.getJSON(url, function(data) { + console.log(data); + $.each(data, function(i,e) { + $("#templates .scoreLine") + .clone() + .find(".word").text(e.name).end() + .find(".score").text(e.score).end() + .appendTo(".scores") + }); + }) +}); \ No newline at end of file From 3af3ccc059c004fd60d146360b6b654b585c7aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Sun, 10 Apr 2011 13:24:34 +0200 Subject: [PATCH 19/20] =?UTF-8?q?Renomage=20scores.js=20=E2=86=92=20score.?= =?UTF-8?q?js=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/html5/score.html | 2 +- code/html5/{scores.js => score.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename code/html5/{scores.js => score.js} (100%) diff --git a/code/html5/score.html b/code/html5/score.html index 53d1783..d56464b 100644 --- a/code/html5/score.html +++ b/code/html5/score.html @@ -14,7 +14,7 @@ body { - + diff --git a/code/html5/scores.js b/code/html5/score.js similarity index 100% rename from code/html5/scores.js rename to code/html5/score.js From 974d757c4e14191a0c562d37b0f991aafc55caf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Georges=20Dup=C3=A9ron?= Date: Sun, 10 Apr 2011 14:12:18 +0200 Subject: [PATCH 20/20] Couleurs sur la page de scores. --- code/html5/my-extensions.js | 4 ++-- code/html5/pticlic.js | 2 +- code/html5/score.js | 34 ++++++++++++++++++++++++++++++---- code/html5/score.json | 2 +- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/code/html5/my-extensions.js b/code/html5/my-extensions.js index 7e75cee..f3c071f 100644 --- a/code/html5/my-extensions.js +++ b/code/html5/my-extensions.js @@ -1,5 +1,5 @@ -Number.prototype.clip = function(min, max) { - return Math.min(Math.max(this, min), max); +Number.prototype.clip = function(min, max, floor) { + return Math.min(Math.max(floor ? Math.floor(this) : this, min), max); }; function dichotomy(start, isBigger) { diff --git a/code/html5/pticlic.js b/code/html5/pticlic.js index e02f6e4..892fbcf 100644 --- a/code/html5/pticlic.js +++ b/code/html5/pticlic.js @@ -1,6 +1,6 @@ function jss() { + // TODO : réduire le nombre de fitIn ou fitFont, ou bien les précalculer. var w, h; - //w = 480; h=800; w = $(window).width(); h = $(window).height(); diff --git a/code/html5/score.js b/code/html5/score.js index 9adbc3b..bd262d3 100644 --- a/code/html5/score.js +++ b/code/html5/score.js @@ -1,13 +1,39 @@ +function jss() { + var w, h; + w = $(window).width(); + h = $(window).height(); + + var mch = h/8, mnh = h*0.075; + + $("body, html") + .css({ + padding: 0, + margin: 0, + overflow: "hidden", + textAlign: "left" + }); + + $("#screen") + .wh(w, h) + .north($("body").north()); // TODO : par rapport à la fenêtre entière. +} + $(function () { var url = "score.json"; $.getJSON(url, function(data) { console.log(data); - $.each(data, function(i,e) { + $.each(data.scores, function(i,e) { + var percentScore = (e.score - data.minScore) / (data.maxScore - data.minScore); $("#templates .scoreLine") .clone() .find(".word").text(e.name).end() - .find(".score").text(e.score).end() - .appendTo(".scores") + .find(".score") + .text(e.score) + .css("color","rgb("+(255 - 255*percentScore).clip(0,255)+","+(191*percentScore).clip(0,255,true)+",0)") + .end() + .appendTo(".scores"); + jss(); }); - }) + }); + jss(); }); \ No newline at end of file diff --git a/code/html5/score.json b/code/html5/score.json index 5f461a5..c03fd73 100644 --- a/code/html5/score.json +++ b/code/html5/score.json @@ -1 +1 @@ -[{"id":84632,"name":"camion","score":3},{"id":61939,"name":"transbahutage","score":10},{"id":104263,"name":"trimbaler","score":4},{"id":44654,"name":"transporter","score":-2},{"id":38285,"name":"d\u00e9m\u00e9nageur","score":5},{"id":43404,"name":"porter","score":5},{"id":63192,"name":"transports","score":-1},{"id":130473,"name":"enthousiasmer","score":0},{"id":90461,"name":"se trimbaler","score":6},{"id":134609,"name":"baguenauder","score":9}] \ No newline at end of file +{"minScore":-5,"maxScore":10,"scores":[{"id":84632,"name":"camion","score":3},{"id":61939,"name":"transbahutage","score":10},{"id":104263,"name":"trimbaler","score":4},{"id":44654,"name":"transporter","score":-2},{"id":38285,"name":"d\u00e9m\u00e9nageur","score":5},{"id":43404,"name":"porter","score":5},{"id":63192,"name":"transports","score":-1},{"id":130473,"name":"enthousiasmer","score":0},{"id":90461,"name":"se trimbaler","score":6},{"id":134609,"name":"baguenauder","score":9}]} \ No newline at end of file