﻿
/**
* 
* Structure html du "ContextMenu"
*
* ------------------------------------------------------------------------------------------------------------------------------------------------------
*     <asp:TextBox ID="WhatTxt" CssClass="input-text" runat="server"></asp:TextBox>
*
*     <div class="contextMenuSearchbox">
*         <div class="menuSearchbox">
*             <div class="loading"><img alt="" class="loading" src="/Img/loading.gif" /></div>
*             <div class="result"></div>
*             <div class="empty"><asp:Localize ID="EmptyResultLocal" Text="Aucun résultat" EnableViewState="false" runat="server"></asp:Localize></div>
*         </div>
*     </div>
* ------------------------------------------------------------------------------------------------------------------------------------------------------
*
*
*
* opt = {
*     inputName           : Identifiant du champ texte devant contenir le "ContextMenu" (EX: .input-text)
*     itemName            : Identifiant des "items" du "ContextMenu" (EX: .contextMenuSearchbox .menuSearchbox .result .item)
*     itemSelectedClass   : Nom de la classe CSS pour les items sélectionnés (EX: itemSelected)
*     contextMenuViewName : Nom du menu "ContextMenu" (EX: .contextMenuSearchbox .menuSearchbox)
*     loadingViewName     : Zone affiché lorsque que le menu est en cours de chargement (EX: .contextMenuSearchbox .menuSearchbox .loading)
*     resultViewName      : Zone pour afficher le contenu du menu (EX: .contextMenuSearchbox .menuSearchbox .result)
*     resultItemViewName  : Zone pour afficher le contenu du menu, (parent des "item") (EX: .contextMenuSearchbox .menuSearchbox .result .results)
*     emptyResultViewName : Zone affiché lorsque le menu est vide (EX: .contextMenuSearchbox .menuSearchbox .empty)
*     errorViewName       : Zone pour afficher un texte d'erreur à la place du menu (EX: Tapez minimum 3 caractères pour lancer la recherche.)
*     codeRunSearch       : Fonction qui va lancer la recherche (si la méthode retourne false, le panneau "errorViewName" est affiché) (EX: function(keyword, onResponseRequest) {...})
*     getHtmlResult       : Fonction qui retourne le résultat de la recherche en HTML (EX: function (result) {...})
*     fireSelectedItem    : (facultatif) Méthode pour avertir qu'un élément à été sélectionné (EX: fireSelectedItem(keywordBeforSelect, jqueryItem) {...})
* }
* 
*/


jQuery.fn.contextMenu = function() {

    // Variables
    var indexSelected = -1;
    var searchTimeout = null;

    // Paramètres
    var inputName = null;
    var itemName = null;
    var itemSelectedClass = null;
    var contextMenuViewName = null;
    var loadingViewName = null;
    var resultViewName = null;
    var resultItemViewName = null;
    var emptyResultViewName = null;
    var errorViewName = null;
    var codeRunSearch = null;
    var getHtmlResult = null;
    var fireSelectedItem = null;


    // "Objet"
    return function(opts) {

        // Init. paramètres
        inputName = opts.inputName;
        itemName = opts.itemName;
        itemSelectedClass = opts.itemSelectedClass;
        contextMenuViewName = opts.contextMenuViewName;
        loadingViewName = opts.loadingViewName;
        resultViewName = opts.resultViewName;
        resultItemViewName = opts.resultItemViewName;
        emptyResultViewName = opts.emptyResultViewName;
        errorViewName = opts.errorViewName;
        codeRunSearch = opts.codeRunSearch;
        getHtmlResult = opts.getHtmlResult;
        if (typeof (opts.fireSelectedItem) == "function") fireSelectedItem = opts.fireSelectedItem;

        // Cache le contextMenu
        closeContextMenu();

        // Désactive la saisie semi-automatique
        jQuery(inputName).attr("autocomplete", "off");

        // Sur la perte de focus
        jQuery(inputName).blur(function(event) {
            clearTimeout(searchTimeout);
            setTimeout(function() { closeContextMenu(); }, 150);
        });

        // On KeyUp (pour le "ContextMenu")
        jQuery(inputName).keyup(function(event) {

            // Si une touche du clavier qui demande le raffraichissement
            if (isRefreshKey(event)) {

                // Affichage ou cache le menu en fonction de la longeur de la recherche
                lengthWord = jQuery(inputName).val().length;
                if (lengthWord > 0) {
                    setLoadingView();
                    setSelectedItem(-1);
                    clearTimeout(searchTimeout);
                    searchTimeout = setTimeout(function() { runSearch(); }, 500);
                }
                else {
                    clearTimeout(searchTimeout);
                    closeContextMenu();
                }
            }
        });

        // On KeyDown (pour la sélection)
        jQuery(inputName).keydown(function(event) {

            // Si le "ContextMenu" est visible
            if (isResultViewVisible()) {

                // Si flèche en bas
                if (event.keyCode == 40) {
                    newIndex = getSelectedItem() + 1;
                    if (newIndex > countItem() - 1) newIndex = -1;
                    setSelectedItem(newIndex);
                }

                // Si flèche en haut
                else if (event.keyCode == 38) {
                    newIndex = getSelectedItem() - 1;
                    if (newIndex < -1) newIndex = countItem() - 1;
                    setSelectedItem(newIndex);
                }

                // Si ESC
                else if (event.keyCode == 27) {
                    closeContextMenu();
                }

                // Si ENTER
                else if (event.keyCode == 13) {
                    if (getSelectedItem() != -1) {
                        validSelectedItem();
                        if (event.preventDefault) event.preventDefault();
                        event.returnValue = false;
                    }
                    else closeContextMenu();
                }
            }

        });


        /**
        * Méthode pour savoir si c'est une touche qui demande la raffraichissement
        */
        function isRefreshKey(event) {
            return event.keyCode != 13 && event.keyCode != 16 && event.keyCode != 40 && event.keyCode != 38 && event.keyCode != 27 && event.keyCode != 37 && event.keyCode != 39 && event.keyCode != 32 && event.keyCode != 226;
        }

        /**
        * Méthode pour lancer la recherche
        */
        function runSearch() {
            keyword = jQuery(inputName).val();
            if (keyword.length > 0) {

                if (codeRunSearch(keyword, onResponseRequest) == false) {
                    setErrorView();
                }
            }
        }

        /**
        * Réponse pour la recherche
        */
        function onResponseRequest(result) {

            html = getHtmlResult(result);
            if (html != null && html != "") {

                jQuery(resultItemViewName).html(html);
                setResultView();

                // Ajout listener
                jQuery(itemName).click(validSelectedItem);
                jQuery(itemName).mouseover(function(event) {
                    index = jQuery(itemName).index(jQuery(this));
                    setSelectedItem(index);
                });
            }
            else setEmptyView();
        }

        /**
        * Méthode pour valider la sélection
        */
        function validSelectedItem() {
            if (getSelectedItem() != -1) {

                selectedIndex = getSelectedItem();
                selectedItem = jQuery(itemName + ":eq(" + selectedIndex + ")");
                selectedText = null;

                keywordBeforSelect = jQuery(inputName).val();
                if (fireSelectedItem != null) {
                    selectedText = fireSelectedItem(keywordBeforSelect, selectedItem);
                }

                closeContextMenu();
                if (selectedText != null) jQuery(inputName).focus().val(selectedText);
                else jQuery(inputName).focus().val(keywordBeforSelect);
            }
        }

        /**
        * Méthode pour compter le nombre "d'item"
        */
        function countItem() {
            return jQuery(itemName).size();
        }

        /**
        * Retourne l'index sélectionné. (-1 si aucune sélection)
        */
        function getSelectedItem() {
            return indexSelected;
        }

        /**
        * Change la sélection
        */
        function setSelectedItem(index) {
            if (getSelectedItem() != -1) jQuery(itemName + ":eq(" + getSelectedItem() + ")").removeClass(itemSelectedClass);
            if (index != -1) jQuery(itemName + ":eq(" + index + ")").addClass(itemSelectedClass);
            indexSelected = index;
        }

        /**
        * Permet de savoir si le "ResultView" est visible
        */
        function isResultViewVisible() {
            return jQuery(resultViewName).is(":visible") && jQuery(contextMenuViewName).is(":visible");
        }

        /**
        * Méthode pour fermer le "ContextMenu"
        */
        function closeContextMenu() {
            showContextMenuView(false);
            showEmptyView(false);
            showLoadingView(false);
            showResultView(false);
            showErrorView(false);
        }

        /**
        * Méthode pour afficher la vue : "Résultat"
        */
        function setResultView() {
            showEmptyView(false);
            showLoadingView(false);
            showResultView(true);
            showErrorView(false);
            showContextMenuView(true);
        }

        /**
        * Méthode pour afficher la vue : "Chargement"
        */
        function setLoadingView() {
            showResultView(false);
            showEmptyView(false);
            showLoadingView(true);
            showErrorView(false);
            showContextMenuView(true);
        }

        /**
        * Méthode pour afficher la vue : "Résultat est vide"
        */
        function setEmptyView() {
            showResultView(false);
            showLoadingView(false);
            showEmptyView(true);
            showErrorView(false);
            showContextMenuView(true);
        }

        /**
        * Méthode pour afficher la vue : "Erreur"
        */
        function setErrorView() {
            showResultView(false);
            showLoadingView(false);
            showEmptyView(false);
            showErrorView(true);
            showContextMenuView(true);
        }

        /**
        * Méthode pour afficher ou cacher le ContextMenu
        */
        function showContextMenuView(b) {
            if (b) jQuery(contextMenuViewName).slideDown("fast");
            else jQuery(contextMenuViewName).slideUp("fast");
        }

        /**
        * Méthode pour afficher ou cacher l'image de chargement
        */
        function showLoadingView(b) {
            if (b) jQuery(loadingViewName).show();
            else jQuery(loadingViewName).hide();
        }

        /**
        * Méthode pour afficher ou cacher le DIV de résultat
        */
        function showResultView(b) {
            if (b) jQuery(resultViewName).show();
            else jQuery(resultViewName).hide();
        }

        /**
        * Méthode pour afficher ou cacher le DIV de résultat vide
        */
        function showEmptyView(b) {
            if (b) jQuery(emptyResultViewName).show();
            else jQuery(emptyResultViewName).hide();
        }

        /**
        * Méthode pour afficher ou cacher le DIV de erreur
        */
        function showErrorView(b) {
            if (b) jQuery(errorViewName).show();
            else jQuery(errorViewName).hide();
        }


    };
};