Avri Blog

Blog à l'avricot - Lord Of Castle, java, nosql, Utomia, AvriChat, javascript, Json, Css, Mootools, ajax, php...

Aller au contenu | Aller au menu | Aller à la recherche

Stop Bubble | Start

Mot-clé - Mootools

Fil des billets - Fil des commentaires

lundi, octobre 19 2009

Comet Javascript : the avriComet from moo-comet !

Lady and gentleman, this is the AvriComet !
It's very very inspired by moo-comet (Benjamin Hutchins) who have done a realy great work !
I have add a new method for comet for Firefox and make some changes.
If you have no idea of what is comet, you can see an exemple of the moo-comet on Benjamin Hutchins' web site
If you want more information about each solution used for each browser, check here : step by step comet tutorial

Download uncompressed 
  1. /*
  2. * @project AvriComet- Mootools 1.2.1> Request.Queue Class (in the function send), Can be found on www.clientcide.com
  3. * @author : Quentin Ambard
  4. * @version : 0.1
  5. * @url http://www.avricot.com/blog
  6. * @license MIT Style License
  7. *
  8.  
  9. it will create 4 differents types of tunnels, using the lasts specifications :
  10. it's -i think- the best solution, but the server will have to send all the informations in 4 differents ways...
  11. ->Trident : iframeForever (using ActiveXObject)
  12. Server :
  13. Specific Header :
  14. Content-Type: text/html; charset=utf-8
  15. Push :
  16. <script type="text/javascript">parent._cometObject.fireEvent('dataPushed', {JSON: "DATA TO PUSH"})</script>
  17. You must flush the buffer, sending some noise when you start the connexion, for exemple :"<span></span><span></span><span></span><span></span><span></span>"
  18. ->presto : source-event
  19. Server :
  20. Specific Header :
  21. Content-Type: application/x-dom-event-stream
  22. Push :
  23. Event: "+this.cometName+"\ndata: {JSON: "DATA TO PUSH"}\n\n (cometName is send on each Bayeux Publish request on the field ex )
  24. ->gecko : xhr object using multipart
  25. Server :
  26. Specific Header :
  27. Content-Type: multipart/x-mixed-replace;boundary=XXoXoX
  28. Push :
  29. Content-Type: text/json\r\n\r\n{JSON: "DATA TO PUSH"}\r\n\r\n--XXoXoX\r\n
  30.  
  31. ->Others : addCallback
  32. Server :
  33. Specific Header :
  34. none
  35. Push :
  36. {JSON: "DATA TO PUSH"}
  37.  
  38.  
  39.  
  40. AvriComet will fire 2 events :
  41. - error ('error text') ;
  42. - push (Object)
  43. When you send data to the server, you can do it throught the method send(whateverYouHaveToSend).
  44. It will catch the answer and fire the event :
  45. - answer (theAnswer)
  46.  
  47. */
  48. var AvriComet = new Class ({
  49. Implements: [Options, Events],
  50. options: {
  51. cometName: "MooComet", //name of the comet connexion, essential for presto engine.
  52. urlServer: '' //Url of the server.
  53. },
  54. length: 0,
  55. initialize: function(_options){
  56. this.setOptions(_options);
  57.  
  58. this.sender = new Request.Queue({
  59. concurrent : 2
  60. });
  61.  
  62.  
  63. this.cometType = (Browser.Engine.trident ? 3 : (Browser.Engine.presto ? 2 : (Browser.Engine.gecko ? 1 : 0)));
  64.  
  65. //ie
  66. if (this.cometType == 3) {
  67. this.tunnel = new ActiveXObject("htmlfile");
  68. }
  69. //presto (opera)
  70. else if (this.cometType == 2){
  71. this.tunnel = document.createElement("event-source");
  72. }
  73. //gecko (firefox)
  74. else if (this.cometType == 1){
  75. this.tunnel = new Request({
  76. url: this.options.urlServer,
  77. method: 'get',
  78. header: ''
  79. });
  80. this.tunnel.xhr.multipart = true ;
  81. this.tunnel.xhr.onload = function (event) {
  82. if (event.target.readyState == 4 ) {
  83. this.decodeJSON(event.target.responseText) ;
  84. //this.fireEvent('dataPushed', [event.target.responseText, event.target.responseXML]) ;
  85. }
  86. else {
  87. this.fireEvent('error', "Error xhr : readyState: "+event.target.readyState) ;
  88. }
  89. }.bind(this.tunnel);
  90. }
  91. //webkit (chrome/safari)
  92. else if (this.cometType == 0){
  93. this.tunnel = new Request.XHR(this.options);
  94. this.tunnel.addCallback(this.onChange.bind(this), {readyState: false, status: false});
  95. }
  96. return this;
  97. },
  98. /**
  99. * Have to be invoked when you want to close the connection
  100. */
  101. cancel: function() {
  102. if (this.cometType == 3) {
  103. this.tunnel.body.innerHTML="<iframe src='about:blank'></iframe>";
  104. }
  105. //default iframe forever for all broswer or just for browser != than presto && gecko
  106. else if (this.cometType == 2) {
  107. document.body.removeChild(this.tunnel);
  108. }
  109. else {
  110. this.tunnel.cancel();
  111. }
  112. return this;
  113. },
  114. /**
  115. * Create the tunnel with the server.
  116. * 3 differents type of tunnel, depends of the browser's engine:
  117. * trident => iframe with ActiveXObject object
  118. * presto => event-source (html5)
  119. * firefox => XMLHttpRequest with multipart
  120. * post the information with : src="'+this.options.urlServer+_post'"
  121. **/
  122. initTunnel: function(_post) {
  123. //Trident Engine (ie)
  124. if (this.cometType == 3) {
  125. this.tunnel.open();
  126. this.tunnel.write("<html><body></body></html>");
  127. this.tunnel.close();
  128. this.tunnel.parentWindow._cometObject = this;
  129. this.tunnel.parentWindow._cometObject.addEvent('dataPushed', this.firePush.bindWithEvent(this));
  130. this.tunnel.body.innerHTML = "<iframe id='test' src='"+this.options.urlServer+'?cometType='+this.cometType+'&cometName='+this.options.cometName+'&'+_post+"'></iframe>";
  131. }
  132. //Presto Engine (opera)
  133. else if (this.cometType == 2) {
  134. this.tunnel.addEventListener(this.options.cometName, this.decodeJSON.bindWithEvent(this), false);
  135. this.tunnel.setAttribute("src", this.options.urlServer+'?cometType='+this.cometType+'&cometName='+this.options.cometName+'&'+_post);
  136. }
  137. //gecko Engine (Firefox)
  138. else //if (this.cometType == 1)
  139. {
  140. //this.tunnel.addEvent('dataPushed', this.decodeJSON.bindWithEvent(this));
  141. this.tunnel.send('cometType='+this.cometType+'&cometName='+this.options.cometName+'&'+_post);
  142. }
  143. //safari+chrome
  144. /*else {
  145. this.tunnel.send({data: {'cometType': this.cometType, 'cometName': this.options.cometName}});
  146. }*/
  147. },
  148. send: function (_post) {
  149. var req = new Request.JSON({url: this.options.urlServer, link: 'cancel', method: 'get'});
  150. req.addEvent('complete', this.answerSender.bindWithEvent(this));
  151. this.sender.addRequest('sender', req);
  152. req.send(_post);
  153. },
  154. decodeJSON: function (_textResponse) {
  155. if(this.cometType == 2) {
  156. _textResponse = _textResponse.data ;
  157. }
  158. else if (_textResponse != "") {
  159. var newLength = text.length ;
  160. if (newLength>this.length) {//fix firefox behaviour when push 2 information in the same time.
  161. _textResponse = text.substring(this.length,newLength-1) ;
  162. /* possible implementation for FF answer (be carreful with the final "," : {JSON: DATA TO PUSH},
  163. *
  164. * text = "["+text.substring(this.length,newLength-1)+"]" ; //So you have [{objectData1},{objectData2},{objectData3}]
  165. var listAction = JSON.decode(text); //you get the array with all the json object from the server
  166. var size = listAction.length ;
  167. for(i=0;i<size;i++) {
  168. this.firePush(listAction[i]);
  169. }
  170. this.length = newLength ;
  171.  
  172. */
  173. }
  174. }
  175. this.firePush(_textResponse);
  176. },
  177. firePush: function (_object) {
  178. try {
  179. if (typeof _object != "object") {
  180. _object = JSON.decode(_object);
  181. }
  182. }
  183. catch (e) {
  184. this.fireEvent('error', 'transmission error or server error. Sometimes the last bracket has a little bug : '+_object);
  185. }
  186. this.fireEvent('push', JSON.decode(_object));
  187. },
  188. answerSender: function (_answer) {
  189. if (typeof(_answer) != "undefined") {
  190. this.fireEvent('answer', _answer);
  191. }
  192. }
  193.  
  194. }) ;
  195.  
  196. Request.XHR = new Class({
  197. Extends: Request,
  198. callbacks: [],
  199. check: function() {
  200. return true;
  201. /*if (!this.timer) return true;
  202. switch (this.options.link){
  203. case 'cancel': this.cancel(); return true;
  204. case 'chain': this.chain(this.start.bind(this, arguments)); return false;
  205. }
  206. return false;*/
  207. },
  208. addCallback: function(fn, options){
  209. options = $extend({
  210. fn: $empty,
  211. readyState: 4,
  212. status: 200
  213. }, options);
  214. this.callbacks.push($extend(options, {fn: fn}));
  215. return this;
  216. },
  217. onStateChange: function(){
  218. //if (!this.running) return;
  219. this.status = 0;
  220. $try(function(){
  221. this.status = this.xhr.status;
  222. }, this);
  223. this.response = {text: this.xhr.responseText, xml: this.xhr.responseXML};
  224. this.callbacks.forEach(function(callback) {
  225. if (callback.readyState != false && callback.readyState != this.xhr.readyState)
  226. return;
  227. if (callback.status != false && callback.status != this.status)
  228. return;
  229. callback.fn(this.processScripts(this.response.text), this.response.xml);
  230. }, this);
  231. }
  232. });


Coming soon :)
This isn't the final version....

samedi, septembre 12 2009

AvriCard : how to manage cards !

AvriCard :

AvriCard is a little MooClass designed for Lord Of Castle New Frontier.
There is no many options, because it's for a very specific usage, but it's easy to add some features if you need it !
It's not based on Drag.moves class and droppables Element, because I dont like the fact you need to have the mouse over the element to start the event. If you have big cards it can be bad !

Download AvriCard ( AvriDeck + AvriCardSlot):

download uncompressed

Exemple :

demo : (just drag the cards over the slots)

Syntax :

  1. // The most easy way :
  2. //we first create a couple of deck
  3. var deck1 = new AvriDeck ($('deck1'),{top: 400, left: 100, zIndex: 9999});
  4. var deck2 = new AvriDeck ($('deck2'),{top: 400, left: 300, zIndex: 9999});
  5. var deck3 = new AvriDeck ($('deck3'),{top: 400, left: 500, zIndex: 9999});
  6. //next we create the slots
  7. avriSlot = new AvriCardSlot([deck1, deck2, deck3], 'cardSlot', {container: 'divCarte', widthCard: 165, widthSlot: 240, heightSlot: 213, numSlot: 4, urlOverLight: './contourLumineux.png'});

Options :

AvriCardSlot

  • container: '', // The id of your container (limit of the card's drag)!
  • widthCard: 165, // int !
  • widthSlot: 200, // int (can be > widthCard, if there is a free espace between 2 slot):
  • heightSlot: 300, // int
  • numSlot: 20, // int

Methods :

none

ChangeLog :

v 0.1 - 12 September, 2009

  • first release

v 0.1.1 - 14 September, 2009

  • Tips bug fixed

mardi, juin 2 2009

AvriHtmlMaps : quick draw :)

AvriHtmlMap

I was bored to draw all my html maps using photoshop in order to find more or less the good coordinate of my polys.
So I have created a small mooClass in order to draw the map directly on the image.
It's based on canvas & ofc mootools :)

Download AvriHtmlMap

download uncompressed

Exemple :

demo :

Syntax :

(Here is the php code which create the image loaded)

  1. <?php
  2. if (!isset($_FILES['image']) OR $_FILES['image']['error'] > 0)
  3. echo 'Select an image in order to draw the html maps :';
  4. else if ($_FILES['image']['size'] > 5000*12000)
  5. echo 'Erreur lors de l\'envoi. <br />Le fichier selectionné est trop volumineux. <br />Réduisez sa taille (en utilisant Paint par exemple).';
  6. else
  7. {
  8. $ext = strtolower(substr(strrchr($_FILES['image']['name'],'.'),1));
  9. if (!in_array(strtolower($ext),array('png','gif','jpg','jpeg')))
  10. echo 'Erreur lors de l\'envoi. <br />Extension incorrecte.';
  11. else
  12. {
  13. $fp = fopen($_FILES['image']['tmp_name'], "r");
  14. $content = fread($fp, filesize($_FILES['image']['tmp_name']));
  15. echo '<img id="img" src="data:image/jpg;base64,'.base64_encode($content).'" />' ;
  16. fclose($fp);
  17. }
  18. }
  19.  
  20. ?>

mardi, avril 28 2009

AvriBubble : a very ligth 2D engine based on Mootools

AvriBubble :

AvriBubble is a little 2D engine which allows you to play with round. It's without Canvas (so elements can't turn on themself !)
It allows you to add gravity, friction and a lot of AvriBubble ;)
You can change the mass, size and speed of each Bubble

Download AvriBubble & AvriContainer :

download uncompressed

Exemple :

demo 1 :
demo 2 :
demo 3 :

Syntax :

  1. // The most easy way :
  2. //we first define the main container
  3. container = new AvriContainer () ;
  4. //we add some bubble to this container
  5. container.add(new AvriBubbule ('bubble1'));
  6. container.add(new AvriBubbule ('bubble2', {mass: 500, isDraggable: false, step: 1}));
  7. container.add(new AvriBubbule ('bubble3'));
  8. //let's play !
  9. container.start();

Options :

AvriContainer

  • top: 50, // int : The top position of your container !
  • left: 50, // int : The left position of your container !
  • height: 200, // int : The height of your container !
  • width: 300, // int : The widthof your container !
  • speed: 20, // int : define in ms. the time between 2 deplacement of each bubble. (it's a perdical() )
  • randomChange: 1, //int : if 1 : will never change the direction of the speed vector. If <1 will change ! (see demo 3)
  • detectColision: true, //boolean : if true, will detect the colision between the bubble
  • gravity : 1, //int : set the gravity. 0 = no-gravity, 10 and > = very very eavy gravity !!
  • friction : 0.9, //int 0...1set the friction wich occurs at each bounce. 1 = no-friction,
  • displayBorder : true //boolean : if true will add a div with .container class wich has the same dimention than the container.

AvriBubble

  • step: 5, // int : define the initial speed of the bubble
  • mass: 'prop', //int or 'prop' : define the mass of the bubble. If 'prop' will be proportionnel to the radius of the bubble
  • isDraggable: true //boolean : allows to drag the bubble or not

Methods :

AvriContainer

  • start () //start the mouvement
  • stop () //stop the mouvement
  • add (AvriBubble) //add a bubble to the container
  • fireEvent('colision', function (bubble1, bubble2) //throw at each colision. You get a wall if it hurt a wall (wall.el.id ='wall')

ChangeLog :

v 0.1.2 - 29 Avril , 2009

  • Now works with divs and not img (beacause of ie drrag bug)
  • "Snap" remove : you dont have to move the mouse to catch a bubble

v 0.1.1 - 29 Avril , 2009

  • syntax improve
  • fix some little bug

v 0.1 - 28 Avril , 2009

  • first release

dimanche, avril 26 2009

Gérez vos inputs : Input Class

Utilité :

  • Permet de modifier le comportement des inputs.
  • Rajoute par défaut la roulette de la souris pour rajouter/enlever un élément de l'input.
  • Permet de fixer des limites maxi et mini à ne pas dépasser aux inputs.
  • Permet de definir directement une fonction qui se déclenchera lorsque l'input change de valeur (keyup, keydow, change, mousewheel)

Telechargement :

telecharger uncompressed

Exemple :

demo :

Syntax :

  1. var inputText = new Input ('exemple', {defaut: 54}) ;
  2. inputText .setLimiteMin('inf') ;//enleve la limite min
  3.  
  4. //premier argument : fonction à effectuer aux changements,
  5. //second argument : si true la fonction sera aussi activée au mouseMouve
  6. //(seule facon de detecter le rajout de texte dans l'input avec un glissé avec la selection de la souris
  7. inputText.setOnChange(function () {alert('changé !');}, true);
  8.  
  9. inputText .removeOnChange() ;//annule la ligne precedente

Option :

  • wheel : boolean (active désactive de base la roulette) defaut : true
  • limiteMax : int ou String (limite maxi à ne pas dépasser, 'inf' pour désactiver la limite) defaut : 'inf'
  • limiteMin : int ou String (limite mini à ne pas dépasser, 'inf' pour désactiver la limite) defaut : 0
  • defaut : int (value de base de l'int) defaut : 0
  • stepWheel : int (valeur à incrementer à chaque coup de wheel) defaut : 1

ChangeLog :

v 0.3 - 28 Avril , 2009

  • rajout de stepWheel
  • Amélioration de setOnChange() et removeOnChange() pour pouvoir envoyer plusieurs fonctions et ne pas ecraser les autres.

v 0.2 - 26 Avril , 2009

  • Adapter pour mootools
  • Rajout de setOnChange() et removeOnChange()

jeudi, avril 16 2009

Class Json en Php pour mootools

J'ai créé une classe Json en php qui permet de manipuler rapidement et instinctivement les propriétés du DOM et de créer des objets json. La classe nécessite le support de json_encode() (version 5.2 de php)

Voici le code de la classe Json

  1. <?php
  2. /*
  3. * @project PhPJson
  4. * @author : Quentin Ambard
  5. * @version : 0.2
  6. * @url http://avriblog.avricot.com
  7. * @license MIT Style License
  8. */
  9. class Json
  10. {
  11. private static $json = array() ;
  12. private static $jsonDOM = array() ;
  13.  
  14. public static function add($key, $value)
  15. {
  16. JSON::$json[$key] = $value ;
  17. }
  18. public static function addArray($key, $value)
  19. {
  20. JSON::$json[$key][] = $value ;
  21. }
  22. private static function jsonGetElementDom($idElement, $property, $value)
  23. {
  24. $nbreE = count(JSON::$jsonDOM) ;
  25. $e = NULL ;
  26. for ($i=0;$i<$nbreE;$i++)
  27. {
  28. if(JSON::$jsonDOM[$i]->idElement == $idElement)
  29. $e = & JSON::$jsonDOM[$i] ;
  30. }
  31. if($e == NULL)
  32. {
  33. $e = & JSON::$jsonDOM[] ;
  34. $e->idElement = $idElement ;
  35. }
  36. return $e ;
  37. }
  38. public static function addProperty($idElement, $property, $value)
  39. {
  40. $e = JSON::jsonGetElementDom($idElement, $property, $value) ;
  41. $e->property->$property = $value ;
  42. }
  43. public static function addStyle($idElement, $property, $value)
  44. {
  45. $e = JSON::jsonGetElementDom($idElement, $property, $value) ;
  46. $e->property->styles->$property = $value ;
  47. }
  48. public static function getEncoded()
  49. {
  50. //on rajoute les modifications du dom pour qu'elles soient gerées tout à la fin par le js.
  51. JSON::$json['DOM'] = JSON::$jsonDOM ;
  52. return json_encode(JSON::$json);
  53. }
  54. public static function error($error)
  55. {
  56. $e->erreur = $error ;
  57. die(json_encode($e));
  58. }
  59. }
  60. ?>

Grace à mootools on récupère directement l'objet Json généré par php et execute directement les changements sur le DOM ! Voici un petit exemple d'utilisation avec mootools et la fonction set():

  1. var ParseurJson = function()
  2. {
  3.  
  4. this.erreur = function(_erreur){
  5. alert('ceci est une erreur :'+_erreur);
  6. }
  7. this.info = function (_info){
  8. alert('ceci est une info:'+_info);
  9. }
  10. this.DOM = function (_DOM){
  11. //On parcours tous les elements à modifier :
  12. var i=0;
  13. while(typeof(_DOM[i]) != "undefined"){
  14. //Si on modifie les proprietée de l'element
  15. if(typeof(_DOM[i].property) != "undefined"){
  16. $(_DOM[i].idElement).set(_DOM[i].property);
  17. }
  18. i++;
  19. }
  20. }
  21. this.parseJson = function (_json) {
  22. var i ;
  23. for (i in _json)
  24. this[i] (_json[i]);
  25. }
  26. this.request = function (_page, _variable){
  27. var requete = new Request.JSON({url: _page});
  28. requete.addEvent('onSuccess', this.parseJson.bindWithEvent(this));
  29. requete.post(_variable);
  30. }

Il ne vous reste plus qu'à utiliser directement la classe en PHP. Par exemple testJson.php qui sera appelé en ajax :

  1. //pour modifier le contenu innerHTML via mootools
  2. JSON::addProperty('id de l\'element à modifier', 'html', 'nouveau contenu') ;
  3. //pour modifier le src d'un element
  4. JSON::addProperty('id de l\'element à modifier', 'src', 'nouveau lien') ;
  5. //pour modifier le style d'un element
  6. JSON::addStyle('id de l\'element à modifier', 'display', '') ;
  7. JSON::addStyle('id de l\'element à modifier', 'color', '#FFF') ;
  8. //Pour envoyer une info :
  9. JSON::add('info', 'valeur de "valeurDeTest" recu : '.$_POST('valeurDeTest')) ; //fait un alert() affichant 'valeur de "valeurDeTest" recu : toto'
  10. //pour creer un objet contenant plusieurs sous-objet et les rajouter au fur et a mesure via php
  11. //A noter que vous pouvez aussi directement passer un array en utilisant addJson(), mais des fois addJsonArray() se revele bien pratique !
  12. JSON::addArray('nom de l\'array', 'var 1') ;
  13. JSON::addArray('nom de l\'array', 'var 2') ;
  14.  
  15. //on ecrit l'ensemble du json generé
  16. echo JSON::getEncoded();

et ensuite on appelle la page en ajax par exemple :

  1. var parseurJson= new ParseurJson{) ;
  2. parseurJson.request ('testJson.php', {valeurDeTest: 'toto', valeurDeTest2: 'toto2'});