web-dev-qa-db-fra.com

Twitter Bootstrap 3 menu déroulant disparaît lorsqu'il est utilisé avec prototype.js

J'ai un problème lors de l'utilisation de bootstrap 3 & prototype.js ensemble sur un site Web magento.

Fondamentalement, si vous cliquez sur le menu déroulant (Nos produits) puis cliquez sur l'arrière-plan, le menu déroulant (Nos produits) disparaît (prototype.js ajoute "display: none;" au li).

Voici une démo du problème: http://ridge.mydevelopmentserver.com/contact.html

Vous pouvez voir que le menu déroulant fonctionne comme il se doit sans inclure prototype.js sur la page du lien ci-dessous: http://ridge.mydevelopmentserver.com/

Quelqu'un d'autre a-t-il déjà rencontré ce problème ou a-t-il une solution possible au conflit?

EASY FIX:

Remplacez simplement le fichier prototype.js de Magento par celui-ci bootstrap amical:

https://raw.github.com/zikula/core/079df47e7c1f536a0d9eea2993ae19768e1f0554/src/javascript/ajax/original_uncompressed/prototype.js

Vous pouvez voir les modifications apportées dans le fichier prototype.js pour résoudre le problème bootstrap ici:

https://github.com/zikula/core/commit/079df47e7c1f536a0d9eea2993ae19768e1f0554

REMARQUE: JQuery doit être inclus dans votre skin magento avant prototype.js .. Exemple:

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/prototype/prototype.js"></script>
<script type="text/javascript" src="/js/lib/ccard.js"></script>
<script type="text/javascript" src="/js/prototype/validation.js"></script>
<script type="text/javascript" src="/js/scriptaculous/builder.js"></script>
<script type="text/javascript" src="/js/scriptaculous/effects.js"></script>
<script type="text/javascript" src="/js/scriptaculous/dragdrop.js"></script>
<script type="text/javascript" src="/js/scriptaculous/controls.js"></script>
<script type="text/javascript" src="/js/scriptaculous/slider.js"></script>
<script type="text/javascript" src="/js/varien/js.js"></script>
<script type="text/javascript" src="/js/varien/form.js"></script>
<script type="text/javascript" src="/js/varien/menu.js"></script>
<script type="text/javascript" src="/js/mage/translate.js"></script>
<script type="text/javascript" src="/js/mage/cookies.js"></script>
<script type="text/javascript" src="/js/mage/captcha.js"></script>
40
MWD

J'ai également utilisé du code d'ici: http://kk-medienreich.at/techblog/magento-bootstrap-integration-mit-prototype-framework mais sans avoir besoin de modifier aucune source. Il suffit de mettre le code ci-dessous quelque part après que le prototype et jquery aient inclus:

(function() {
    var isBootstrapEvent = false;
    if (window.jQuery) {
        var all = jQuery('*');
        jQuery.each(['hide.bs.dropdown', 
            'hide.bs.collapse', 
            'hide.bs.modal', 
            'hide.bs.tooltip',
            'hide.bs.popover',
            'hide.bs.tab'], function(index, eventName) {
            all.on(eventName, function( event ) {
                isBootstrapEvent = true;
            });
        });
    }
    var originalHide = Element.hide;
    Element.addMethods({
        hide: function(element) {
            if(isBootstrapEvent) {
                isBootstrapEvent = false;
                return element;
            }
            return originalHide(element);
        }
    });
})();
42
evgeny.myasishchev

En retard à la fête, mais trouvé ce problème github qui renvoie à cette page d'information qui relie à ce jsfiddle qui fonctionne vraiment bien. Il ne corrige pas sur chaque sélecteur jQuery et est, je pense, de loin le meilleur correctif. Copie du code ici pour aider les futurs peuples:

jQuery.noConflict();
if (Prototype.BrowserFeatures.ElementExtensions) {
  var pluginsToDisable = ['collapse', 'dropdown', 'modal', 'tooltip', 'popover'];
  var disablePrototypeJS = function (method, pluginsToDisable) {
    var handler = function (event) {
      event.target[method] = undefined;
      setTimeout(function () {
        delete event.target[method];
      }, 0);
    };
    pluginsToDisable.each(function (plugin) {
      jQuery(window).on(method + '.bs.' + plugin, handler);
    });
  };


  disablePrototypeJS('show', pluginsToDisable);
  disablePrototypeJS('hide', pluginsToDisable);
}
8
patrickdavey

Il n'est pas conseillé d'utiliser le sélecteur * avec jQuery. Cela prend chaque objet DOM sur la page et le place dans la variable. Je conseillerais de sélectionner les éléments qui utilisent un composant Bootstrap spécifique. La solution ci-dessous utilise uniquement le composant déroulant:

(function() {
    var isBootstrapEvent = false;
    if (window.jQuery) {
        var all = jQuery('.dropdown');
        jQuery.each(['hide.bs.dropdown'], function(index, eventName) {
            all.on(eventName, function( event ) {
                isBootstrapEvent = true;
            });
        });
    }
    var originalHide = Element.hide;
    Element.addMethods({
        hide: function(element) {
            if(isBootstrapEvent) {
                isBootstrapEvent = false;
                return element;
            }
            return originalHide(element);
        }
    });
})();
7
Tom Franssen

Très tard pour la fête: si vous n'avez pas envie d'exécuter des scripts supplémentaires, vous pouvez ajouter un simple remplacement CSS pour éviter qu'il ne soit masqué.

.dropdown {
    display: inherit !important;
}

Généralement, l'utilisation de !important en CSS est déconseillé, mais je pense que cela compte comme une utilisation acceptable à mon avis.

6
CJxD

Le remplacement du fichier prototype.js de Magento par la version bootstrap amicale suggérée par MWD génère une erreur qui empêche l'enregistrement des produits configurables:

Uncaught TypeError: Object [object Array] has no method 'gsub' prototype.js:5826

(Exécution de Magento Magento 1.7.0.2)

la solution evgeny.myasishchev a très bien fonctionné.

(function() {
    var isBootstrapEvent = false;
    if (window.jQuery) {
        var all = jQuery('*');
        jQuery.each(['hide.bs.dropdown', 
            'hide.bs.collapse', 
            'hide.bs.modal', 
            'hide.bs.tooltip'], function(index, eventName) {
            all.on(eventName, function( event ) {
                isBootstrapEvent = true;
            });
        });
    }
    var originalHide = Element.hide;
    Element.addMethods({
        hide: function(element) {
            if(isBootstrapEvent) {
                isBootstrapEvent = false;
                return element;
            }
            return originalHide(element);
        }
    });
})();
2
Perez Jr

voir http://kk-medienreich.at/techblog/magento-bootstrap-integration-mit-prototype-framework/ .

C'est une solution assez simple pour valider l'espace de noms de l'élément cliqué.

Ajoutez une fonction de validation à prototype.js:

et après cela, validez l'espace de noms avant que l'élément ne soit caché:

  hide: function(element) {
    element = $(element);
    if(!isBootstrapEvent)
    {
        element.style.display = 'none';
    }
    return element;
  },
2
klma

Cette réponse m'a aidé à me débarrasser du problème de conflit entre bootstrap et prototype.

Comme @ GeekNum88 décrit la question,

PrototypeJS ajoute des méthodes au prototype Element, donc lorsque jQuery essaie de déclencher la méthode hide() sur un élément, il lance en fait la méthode PrototypeJS hide(), qui est équivalente à la fonction jQuery hide() méthode et définit le style de l'élément sur display:none;

Comme vous le suggérez dans la question elle-même, vous pouvez utiliser bootstrap friendly prototype ou bien vous pouvez simplement commenter quelques lignes dans bootstrap comme ci-dessous,

à l'intérieur de Tooltip.prototype.hide fonction

this.$element.trigger(e)
if (e.isDefaultPrevented()) return
0
Janith Chinthana