Bonjour,

Je viens vers vous suite à plusieurs tentative pour étendre un plugin jQuery.

Sujet :

Je suis actuellement entrain de créer un Bundle Symfony2 sur la gestion des menus (front et admin) avec une interface graphique.

Dans cette interface, j'utilise un plugin jQuery qui liste les différents menu avec leur sous-menu (plugin jQtree ). Pour ma part il est très utile mais pour mon usage il manquais des fonctions et paramètres. J'ai donc ajouter ces différentes fonctions et paramètres mais directement dans le code et ce code est sous licence et donc ne peut être redistribuer en étant modifier.

Je veux donc créer une extension de se plugin qui va me permettre de rajouter les différentes fonctions que j'ai rajouter et paramètres.

Problème :

Suite à plusieurs tentative. J'ai beau essayer plusieurs synthaxe pour l'étendre, aucune ne fonctionne.

Composition du plugin :

Dans le plugin il y a ceci :

(function() {

  // D'autre objets

Node = (function() {
    function Node(o, is_root, node_class) {
      if (is_root == null) {
        is_root = false;
      }
      if (node_class == null) {
        node_class = Node;
      }
      this.setData(o);
      this.children = ];
      this.parent = null;
      if (is_root) {
        this.id_mapping = {};
        this.tree = this;
        this.node_class = node_class;
      }
    }
    // D'autre fonctions ....

      return Node;

  })();

  this.Tree.Node = Node;

// D'autre objets

}).call(this);

J'ai donc voulu rajouter mes nouvelle fonctions avec plusieurs synthaxe comme :

(function($) {
    $.fn.Node = function() {

    getPositionChildrenOfParent = function() {
      var next_index;
      if (!this.parent) {
        return null;
      } else {
        childrens_total = this.parent.countChildrens();
        index = this.parent.getChildIndex(this) + 1;
        console.log('new_node', index);
        if (index === 1) {
          return 'firstChild';
        }else if(index === childrens_total){
          return 'lastChild';
        }else{
          return index;
        }
      }
    };

    $.extend($.fn.Node,getPositionChildrenOfParent);

    countChildrens = function() {
      var next_index;
      if (!this.parent) {
        return null;
      } else {
        return this.children.length;
      }
    };

    firstOrLastChild = function() {
      var next_index;
      if (!this.parent) {
        return null;
      } else {
        childrens_total = this.parent.countChildrens();
        index = this.parent.getChildIndex(this) + 1;
        if (index === 1) {
          return 'firstChild';
        }else if(index === childrens_total){
          return 'lastChild';
        }else{
          return null;
        }
      }
    };

    getNewPosition = function(parent) {
      var next_index;
      if (!this.parent) {
        return null;
      } else {
        var position;
        console.log('getPositionThis', this);
        console.log('parent', parent);
        if (this.haveSameParent(parent)) {
          position = this.getPositionChildrenOfParent();
          console.log('parent_in', parent);
          var previous_position = parent.getNodeById(this.id);
          var new_position = this.getPositionChildrenOfParent();
          return 'previous :'+previous_position+' -------- new : '+new_position;
          //return 'ok';
        }else{
          var new_node = this.tree.getNodeById(this.id);
          /*console.log('new_node',new_node);*/
          position = new_node.getPositionChildrenOfParent();
          return this.getPositionChildrenOfParent();
        }

      }
    };

    haveSameParent = function(parent) {
      if (!this.parent) {
        return null;
      } else {
        if (this.parent.id === parent.id) {
          return true;
        }else{
          return false;
        }
      }
    };

    _updateNodePosition = function() {

    };

      return this
    }
})(jQuery);

OU :

(function($) {
    $.fn.Node = function() {

     var n = this;
     var newNode = {

            this.prototype.getPositionChildrenOfParent = function() {
              var next_index;
              if (!this.parent) {
                return null;
              } else {
                childrens_total = this.parent.countChildrens();
                index = this.parent.getChildIndex(this) + 1;
                console.log('new_node', index);
                if (index === 1) {
                  return 'firstChild';
                }else if(index === childrens_total){
                  return 'lastChild';
                }else{
                  return index;
                }
              }
            };

            this.prototype.countChildrens = function() {
              var next_index;
              if (!this.parent) {
                return null;
              } else {
                return this.children.length;
              }
            };

            this.prototype.firstOrLastChild = function() {
              var next_index;
              if (!this.parent) {
                return null;
              } else {
                childrens_total = this.parent.countChildrens();
                index = this.parent.getChildIndex(this) + 1;
                if (index === 1) {
                  return 'firstChild';
                }else if(index === childrens_total){
                  return 'lastChild';
                }else{
                  return null;
                }
              }
            };

            this.prototype.getNewPosition = function(parent) {
              var next_index;
              if (!this.parent) {
                return null;
              } else {
                var position;
                console.log('getPositionThis', this);
                console.log('parent', parent);
                if (this.haveSameParent(parent)) {
                  position = this.getPositionChildrenOfParent();
                  console.log('parent_in', parent);
                  var previous_position = parent.getNodeById(this.id);
                  var new_position = this.getPositionChildrenOfParent();
                  return 'previous :'+previous_position+' -------- new : '+new_position;
                  //return 'ok';
                }else{
                  var new_node = this.tree.getNodeById(this.id);
                  /*console.log('new_node',new_node);*/
                  position = new_node.getPositionChildrenOfParent();
                  return this.getPositionChildrenOfParent();
                }

              }
            };

            this.prototype.haveSameParent = function(parent) {
              if (!this.parent) {
                return null;
              } else {
                if (this.parent.id === parent.id) {
                  return true;
                }else{
                  return false;
                }
              }
            };
     }

      return this
    }
})(jQuery);

Je ne sait pas comment rajouter des fonctions à des plugins déjà existant.

Si une personne connais ou pourrai me guider pour y arriver je le remercie d'avance

Cordialement,

13 réponses


ksta
Auteur
Réponse acceptée

Salut,

Non tkt je comprend :) ,
J'ai trouver la solution hier soir mais suite à une mauvaise manipe je pensai que ce n'était pas la solution mais j'ai dormi depuis et se matin j'ai corriger mon erreur :D.

Alors en faite ce que je ne comprenais pas c'est pourquoi le plugin était déclarer comme ceci :

(function() {
    // Code du plugin
}).call(this);

Et après quelque recherche et de temps :) j'ai réussi à comprendre.

En faite ce plugin n'étant pas jQuery mais l'objet Window lui même et du coup lors de l'initialisation cela n'enregistrais pas au bonne endroit les fonctions :)

Grâce à toi j'ai réussi à trouver le problème et comprendre un peu mieux l'extension :) j'ai fait un console.log() juste avant le this pour trouver ce qu'étendais ce plugin et on vois que c'est un objet windows se qui ma permis d'utiliser le même principe que le plugin et enfin réussir à l'intégrer :)

Voici le résultat :

(function() {

   /* Debut extension */
    var newMethods = {
        /**
        * @Author Castanares kévin
        * Permet de récupérer le nombre d'enfant d'un parent
        **/
        countChildrens: function() {
          var next_index;
          if (!this.parent) {
            return null;
          } else {
            return this.children.length;
          }
        }
        // autre fonctions ...
    };
    $.extend(true, this.Tree.Node.prototype, newMethods);
    /* Fin extension */
    // Débeug de l'objet que l'on étant = Windows
  console.log(this);
}).call(this);

Grâce à toi j'ai pu m'en rendre compte après plusieurs recherche et enfin trouver :)

Encor merci pour ton aide et d'avoir pris de ton temps pour m'aider :)

Ben il y a la fonction $.extend(), non ?
un truc du genre:

(function($) {
    /* Debut extension */
    var newMethods = {
        newMethods1: function(){
            /* code */
            return /* ... */;
        }
        newMethods2: function(){
            /* code */
            return /* ... */;
        }
    };
    $.extend(true, $[NOMPLUGINDEBASE].prototype, newMethods);
    /* Fin extension */
})(jQuery);

Je sais plus exactement, mais c'est dans ce gout la ...

ksta
Auteur

Je te remercie de ton aide, j'ai donc fait comme ton exemple mais j'ai un problème au niveau de NOMPLUGINDEBASE car le plugin s'appelle jQtree mais se déclare comme ceci :

$('la balise HTML').tree(options ....);

j'ai donc essayer ceci :

// avec tree
$.extend(true, $[tree].prototype, newMethods);
// avec tree.Node
$.extend(true, $[tree.Node].prototype, newMethods);
// avec Node
$.extend(true, $[Node].prototype, newMethods);

Je ne sais pas quoi mettre comme nom de plugin car dans le fichier tree.js il y à plusieurs extensions on dirai (désoler je suis pas encore très a l'aise avec l'extension jquery) exemple du fichier :

(function() {
    SimpleWidget = (function() {
        // code ..
     })();
  this.SimpleWidget = SimpleWidget;
  /*
This widget does the same a the mouse widget in jqueryui.
*/

    MouseWidget = (function(_super) {
        // code ..
    })(SimpleWidget);
      this.Tree = {};

    Node = (function() {
       // code ...
    })();
      this.Tree.Node = Node;
    etc....
}).call(this);

lien du fichier js : tree.js

Merci encore pour ton aide

Essaye ca, j'ai pris une des méthodes que tu veux ajouter, et ça a l'air de marcher en console pour moi (il ajoute bien la nouvelle méthode, mais j'ai pas testé pour voir si elle est effectivement fonctionnelle):

var newMethods = {
    countChildrens: function() {
        var next_index;
        if (!this.parent) {
            return null;
        } else {
            return this.children.length;
        }
    }

    /* Ajoute ici les autres méthodes de ton extension */
}
$.extend(true, Node.prototype, newMethods);

D'ailleurs je me demande: c'est voulu cette variable inutile, au début de ta fonction ?

ksta
Auteur

A j'avais pas vu :) non elle ne doit pas être la sa doit être quand j'ai fait un copier coller d'une fonction j'ai oublier de l'enlever merci :)

Je viens de tester et en effet cela la rajoute dans la console mais cela la attribuer à jquery et non à Node.

voici mon initialisation du plugin :

$(function() {
    var $tree = $('#tree1');

    var test = $tree.tree({
      data: JSON.parse('{{menuItem|raw }}'),
      dragAndDrop: true,
      openedIcon: '<i class="icon icon-minus-sign"></i>',
      closedIcon: '<i class="icon icon-plus-sign"></i>',
      updateUrl : '{{ path("menu_admin_deplacer") }}',
      onCreateLi: function(node, $li){ 
          $li.find('.jqtree-toggler').addClass('Parent');
          $li.find('.jqtree-title').attr('id', node.id);

          // Append a link to the jqtree-element div.
          // The link has an url '#node-[id]' and a data property 'node-id'.
          $li.find('.jqtree-element').append(
              '<div class="btn-group" style="position:absolute; right:0px; margin-top:5px; margin-right:5px;">\
                <button class="btn btn-info btn-mini">\
                  <a href="#node-'+ node.id +'" class="edit" data-node-id="'+
                            node.id +'">\
                    <i class="icon-white icon-plus"></i>\
                  </a>\
                </button>\
                <button class="btn btn-info btn-mini edit">\
                  <a href="#node-'+ node.id +'" class="" data-node-id="'+
                            node.id +'">\
                    <i class="icon-white icon-pencil"></i>\
                  </a>\
                </button>\
                <button class="btn btn-info btn-mini">\
                  <i class="icon-white icon-remove"></i>\
                </button>\
              </div>\
              '       
          );
          $span = $li.find('.jqtree-toggler').next(); 
          $li.find('.jqtree-toggler').prependTo($span);
      }
    });
  console.log(test);

le console test montre l'objet jqTreeWidget et ces différentes fonctions.

Ce que j'aimerais c'est d'ajouter ces fonctions à jqTreeWidget.tree.node_class

Merci en tous cas de m'aider

ksta
Auteur

On peut voir également dans la console que jqTreeWidget.tree est = Node et c'est à se Node la que je veut rajouter ces fonctions tous les objet Node devrait avoir ces fonctions.

Je pige pas quand tu dis que tu étends jQuery, et non pas Node, avec mon code. Parce que tu étends bien Node en utilisant Node.prototype, normalement ... et si tu affiche Nodes en console, la nouvelle méthode est bien listée a coté des autres ...

ksta
Auteur

De mon coter la fonction n'apparait pas a coter des autre fonctions mais a coter de celle de jquery :(

Comment fait tu pour afficher dans la console que le node?

j'ai fait comme tu ma dit j'ai rajouter le code ci-dessous a la fin du fichier tree.js :

(function() {
 var newMethods = {

    countChildrens: function() {
        var next_index;
        if (!this.parent) {
            return null;
        } else {
            return this.children.length;
        }
    }

    /* Ajoute ici les autres méthodes de ton extension */
}

$.extend(true, Node.prototype, newMethods);

})(jQuery);

et quand je regarde dans firebug mon retour test de l'initialisation du plugin je trouve pas la fonction.

ksta
Auteur

Je vien de voir pour les fonctions, elle sont bien attribuer à Node quand on fait un console.log() juste après le extends mais elle ne sont pas pris en compte lorsque qu'il s'initialise car si on regarde la variable teste de l'initialisation elle ne sont pas dedans bizarre non?

tape mon code (sans la fonction jquery autour: juste la variable newMethods et ce qu'elle contient, ainsi que le $.extend()) dans ta console (Sur ta page, ou bien sur leur site, ici, ou j'ai fait mon test ).

Tu verras que cela retournera ton objet Node, dans lequel apparaît bien la nouvelle méthode countChildrens().
Tiens, je te mets même une image ^^:

ksta
Auteur

En effet moi aussi ils apparaissent :(

mais le problème quand je le met dans le fichier et que je bouge un des menu il me dit :

TypeError: node_element.getPositionChildrenOfParent is not a function
position : node_element.getPositionChildrenOfParent(),

car justement j'ai ajouter toute mes fonctions mais quand on fait un console.log juste après le s.extend(true, Node, newMethods)

j'ai bien comme toi mes fonctions

C'est la ou je comprend pas :(

ksta
Auteur

Voila une image quand je tape comme toi dans la console :

et quand je le met dans le fichier :

Bon, alors je voudrais pas passer pour un lâcheur, mais je vais commencer a sécher :/ ...

Question a deux balles: C'est pas possible pour toi de faire un plugin indépendant, qui utilise simplement le DOM qui est généré par jQtree. Parce que faire un petit script pour parcourir les ul et des li pour compter le nombre des uns et des autres, ca me semble plus viable au final que d'essayer d'étendre ce plugin jQtree bizarrement fait ^^