회원검색을 하는 위젯이 있습니다. 검색어를 넣으면 매칭이 되는 회원을 자동으로 나열해 주는 위젯입니다. 회원의 닉네임을 찾거나 할때 편리합니다.

 

그런데 파이어폭스에서는 동작이 좀 상이해서 사용하기 어려운 점이 있어서요.

 

증상 : 검색어를 입력하고 스페이스로 한칸을 띄우고 다시 백스페이스로 공백을 줄여줘야 동작을 합니다.

 

다른 브라우저는 이증상이 없이 그냥 검색어 입력한 후 따로 스페이스로 한칸을 띄웠다가 다시 공백을 없애주는 동작없이 검색어 입력으로 매칭되는 회원이 출력됩니다.

 

js 내용입니다.

 

 

jQuery(function($) {
    /**
     * 필요 전역변수 선언
     */
    var search_target;
    var disp_info;
    var delay_time;
    var sort_order;
    var sort_list;
    var list_count;
    var page = 1;
    var t;
    var length = 0;
    var cur_select = -1;
    var dispMemberInfo = "";
    var width = 0;
    
    /**
     * 문서 로드시 실행되는 메소드들.
     */
    $(document).ready(function() {
        // 전역변수에 값 집어넣고 hidden input 제거
        search_target = $('.user_finder_box .search_target').val();
        disp_info = $('.user_finder_box .disp_info').val();
        delay_time = parseInt($('.user_finder_box .delay_time').val()) * 1000;
        sort_order = $('.user_finder_box .sort_order').val();
        sort_list = $('.user_finder_box .sort_list').val();
        list_count = parseInt($('.user_finder_box .list_count').val());
        page = 1;
        dispMemberInfo = $('.user_finder_box .dispMemberInfo').val();
        dispMemberInfo = dispMemberInfo.replace('z', '');
        width = parseInt($('.user_finder_box .width').val());
        $('.user_finder_box .search_target').remove();
        $('.user_finder_box .disp_info').remove();
        $('.user_finder_box .delay_time').remove();
        $('.user_finder_box .sort_order').remove();
        $('.user_finder_box .sort_list').remove();
        $('.user_finder_box .list_count').remove();
        $('.user_finder_box .dispMemberInfo').remove();
        $('.user_finder_box .width').remove();
        search_target = search_target.split(',');
        disp_info = disp_info.split(',');
        length = 0;
        cur_select = -1;
        $('.user_finder_box .inputbox').val($('.user_finder_box .inputbox').attr('default'));
        
        // 가로 길이 정리
        $('.user_finder_box').css('width', width + 'px');
        $('.user_finder_box .inputbox').css('width', width - 5 + 'px');
        $('.user_finder_box .btnClose').css('left', width - 22 + 'px');
    });
    
    $('.user_finder_box .inputbox').keyup(function(event) {
        page = 1;
        // 화살표 아래, 위 키가 눌러졌다면 선택해준다.
        // 아래 키
        if (event.keyCode == 40) {
            console.log('length = ' + length);
            console.log('cur_select = ' + cur_select);
            // 없을 때 무시, 마지막 항목이 이미 선택되었을 때 무시
            if (length < 1)
                return false;
            if (length == ++cur_select) {
                cur_select--;
                return false;
            }
            lighten_member_info($('.user_finder_box .user_info:eq(' + (cur_select - 1) + ')'));
            darken_member_info($('.user_finder_box .user_info:eq(' + cur_select + ')'));
            return false;
        }
        // 위 키
        else if (event.keyCode == 38) {
            // 하나짜리일 때 무시, 첫 번째 항목이 이미 선택되었을 때 무시
            if (length == 0)
                return false;
            if (cur_select == 0) {
                return false;
            }
            cur_select--;
            lighten_member_info($('.user_finder_box .user_info:eq(' + (cur_select + 1) + ')'));
            darken_member_info($('.user_finder_box .user_info:eq(' + cur_select + ')'));
            return false;
        }
        // 엔터키 눌렀을 때 사용자 정보 페이지로 넘어가기
        else if (event.keyCode == 13) {
            // 선택된게 없다면 취소
            if (cur_select < 0)
                return false;
            var member_srl = $('.user_finder_box .user_info:eq(' + cur_select + ')').attr('member_srl');
            location.href = dispMemberInfo + member_srl;
            return false;
        }
        //올바른 입력키가 입력되었는지 확인
        if (!isValidInputKey(event)) {
            return false;
        }
        // 키가 눌러진 후 몇 초간 간격 뒤에 찾기 알고리즘 실행
        var $that = $(this);
        clearTimeout(t);
        t = setTimeout(function() {
            var responses = ['member_list'];
            var params = {};
            params['search_keyword'] = $that.val();
            if ($that.val() == '') {
                $('.user_finder_box .user_info').remove();
                length = 0;
                cur_select = -1;
                return false;
            }
            for (var i in search_target) {
                params[search_target[i]] = $that.val();
            }
            params['sort_order'] = sort_order;
            params['sort_list'] = sort_list;
            params['list_count'] = parseInt(list_count) + 1;
            params['page'] = page;
            exec_xml('user_finder', 'getUser_finderMemberList', params, completeGetUserFinder, responses);
        }, delay_time);
    });
    
    function completeGetUserFinder(ret_obj) {
        // 만약에 기존에 사용자 정보를 담은 필다가 있다면 그 필드 모두 지우기
        if (page == 1)
            $('.user_finder_box .user_info').remove();
        length = 0;
        cur_select = -1;
        $('.user_finder_box .user_info').each(function() {
            lighten_member_info($(this));
        });
        
        // 요청 실패시 취소
        var message = ret_obj['message'];
        if (message != 'success') {
            $('.user_finder_box .inputbox').val($('.user_finder_box .inputbox').attr('default'));
            $('.user_finder_box .user_info').remove();
            length = 0;
            cur_select = -1;
            $('.user_finder_box .see_more').css('display', 'none');
            return false;
        }
        
        // 받은 사용자 정보를 넣는다.
        var member_list = ret_obj['member_list'];
        
        // 아무것도 받은 것이 없다면 취소
        if (member_list == null) {
            $('.user_finder_box .user_info').remove();
            length = 0;
            cur_select = -1;
            $('.user_finder_box .see_more').css('display', 'none');
            return false;
        }
        
        // member_list.item 이 array 형식이 아닐 경우 array로 변환
        if (!$.isArray(member_list.item)) {
            member_list.item = new Array(member_list.item);
        }
        // 받은 모든 아이템을 박스화로 만들어서 출력시켜준다.
        for (var i in member_list.item) {
            if (i >= list_count)
                break;
            
            var $user_info = $('.user_finder_box .user_info_original').clone();
            $user_info.removeClass('user_info_original');
            $user_info.addClass('user_info');
            $user_info.find('div').addClass('member_' + member_list.item[i]['member_srl']);
            $user_info.css('display', 'block');
            $user_info.attr('order', i);
            $user_info.attr('member_srl', member_list.item[i]['member_srl']);
            
            // 프로필 사진.
            if (member_list.item[i].profile_image != null) {
                $user_info.find('.profile').attr('src', member_list.item[i].profile_image['file']);
            } else {
                $user_info.find('.profile').attr('src', 'widgets/user_finder/skins/default/img/anonymous.jpg');
            }
            // disp_info 에 명시되어있는 3개의 아이템을 출력시켜준다.
            for (var j = 1; j <= 3; j++) {
                if (disp_info[j - 1] == null)
                    break;
                $user_info.find('.inbox_' + j).text(member_list.item[i][disp_info[j - 1]]);
                $user_info.find('.inbox_' + j).addClass(disp_info[j - 1]);
                $user_info.find('.inbox_' + j).removeClass('inbox_' + j);
            }
            // 마우스를 올렸을 때 진해지도록 이벤트 할당
            $user_info.bind('mouseenter', onMouseEnter);
            // 마우스를 내렸을 때 연해지도록 이벤트 할당
            $user_info.bind('mouseleave', onMouseLeave);
            // html element 삽입
            $('.user_finder_box .user_info_original').before($user_info);
        }
        // list_count보다 더 많다면 더보기 버튼 보이기
        if (i >= list_count) {
            $('.user_finder_box .see_more').css('display', 'block');
        } else {
            $('.user_finder_box .see_more').css('display', 'none');
        }
        length = $('.user_finder_box .user_info').length;
    }
    
    /**
     * 최초에 클릭하면 기존에 있던 '사용자를 찾아보세요...' 메시지 없앤다.
     */
    $('.user_finder_box .inputbox').click(function() {
        var theVal = $(this).val().toString();
        var theDef = $(this).attr('default').toString();
        if (theVal != theDef)
            return false;
        else
            $(this).val('');
    });
    
    /**
     * 닫기 버튼을 클릭하면 모든 검색 결과를 없애주고 택스트 박스 글자 원위치
     */
    $('.user_finder_box .btnClose').click(function() {
        $('.user_finder_box .user_info').remove();
        length = 0;
        cur_select = -1;
        $('.user_finder_box .inputbox').val($('.user_finder_box .inputbox').attr('default'));
        $('.user_finder_box .see_more').hide();
    });
    
    /**
     * 더 보기를 눌렀을 때 다음 페이지를 불러오기
     */
    $('.user_finder_box .see_more').click(function() {
        var responses = ['member_list'];
        var params = {};
        page++;
        params['search_keyword'] = $('.user_finder_box .inputbox').val();
        for (var i in search_target) {
            params[search_target[i]] = $('.user_finder_box .inputbox').val();
        }
        params['sort_order'] = sort_order;
        params['sort_list'] = sort_list;
        params['list_count'] = parseInt(list_count) + 1;
        params['page'] = page;
        console.log(params);
        
        exec_xml('user_finder', 'getUser_finderMemberList', params, completeGetUserFinder, responses);
    });
    
    /**
     * 마우스를 올렸을 때 진하게 만듬
     */
    function onMouseEnter(event) {
        // 일단 모든 엘리먼트들을 연하게 만듬.
        $('.user_finder_box .user_info').each(function() {
            lighten_member_info($(this));
        });
        // 마우스 올라간 녀석 진하게 만듬
        darken_member_info($(this));
        // 전역변수 정리하기
        cur_select = $(this).attr('order');
    }
    /**
     * 마우스를 내렸을 때 연하게 만듬
     */
    function onMouseLeave(event) {
        // 처리 안해도 되나???
    }
    
    /**
     * 진하게 만드는 함수
     */
    function lighten_member_info(obj) {
        obj.removeClass('darkened');
    }
    
    /**
     * 연하게 만드는 함수
     */
    function darken_member_info(obj) {
        obj.addClass('darkened');
    }
    
    /**
     * 입력된 키가 올바른 값인지 확인
     * 13(엔터)을 눌렀을 때 사용자 정보 페이지로 넘어가자.
     */
    function isValidInputKey(e) {
        //8(bs), 32(sp), 48 ~ 57(숫자), 65 ~ 90(알파벳), 96 ~ 109(키패드:모질라)
        var k = e.keyCode;
        if ((k == 8) || ((k >= 48)&&(k <= 57)) ||
                ((k >= 65)&&(k <= 90)) || ((k >= 96)&&(k <= 109))) {
            return true;
        }
        return false;
    }
});

/**
 * 학번을 받아서 뒷 자리 2자리를 *표로 가려준다.
 *
function maskStuid(stuid) {
    var t;
    t = stuid.substring(0, stuid.length - 2);
    t += "**";
    return t;
}
*/

  • profile

    파이어폭스는 한글, 한자, 일본어 등 여러 키를 눌러야 하나의 문자가 완성되는 언어를 처리하는 방식이 좀 다릅니다. 이것 때문에 예전엔 에디터에서 자음과 모음이 분리되는 경우도 있었고요.

     

    모든 사용자에게 권해줄 수 있는 해결책은 아니지만, 혹시 about:config 화면에서 intl.tsf.enable 설정을 false로 변경한 후 파폭을 재시작해도 같은 현상인가요? (파폭 주소창에 about:config라고 입력하면 됩니다.)

  • profile profile
    윽... 클라이언트에서 해결해야 할 문제라면 좀 어려운 문제군요. 일단 해보겠습니다.
  • profile profile
    뭔가 바뀌긴 했는데 회원검색 위젯에서는 동일하네요. js에서 수정해서 될게 아니면 그냥 포기해야 할 것 같습니다. 클라이언트들을 다 제가 손봐줄 수 있는 상황이 아니니까요.

    증상이 정확이 어떤 증상이냐면요...
    다른 브라우저는 한글자를 완성하면 커서가 그 글자 앞에 깜빡입니다. 그러면서 해당글자와 매칭이 되는 것을 잘 출력을 해주구요.

    파이어폭스는 글자하나를 완성하면 커서가 아닌 해당글자를 음영 ? 과 같이 선택한 듯한 모습을 합니다. 그래서 그것을 스페이스로 한칸 이동한다음 다시 백스페이스로 해당문자와 커서를 붙여주면 이때 동작을 해요.

    지금 말씀해주신 설정으로 바꿨더니 문자완성후 커서가 생기지는 않고 글자 밑에 점선이 생기네요. 이전에는 글자에 블럭처럼 색칠? 같은거 였거든요.
  • profile profile
    글자를 완성하는 방식만 바뀌고, 방금 입력한 문자는 아직 완성되지 않은 것으로 취급하는 문제는 마찬가지인 모양이네요. 하긴 "웹지기"라고 써놓으면 "웹지기"라고 다 쓴 건지, 아니면 "웹지김"이라고 아직 쓰는 중인지 구분하기가 곤란하잖아요. 확실하지 않으면 이벤트를 안 날리나 봅니다...

    그런데 스페이스를 누르면 입력이 끝난 것이 확실한데, 다시 백스페이스를 눌러서 커서를 붙여줘야 한다니 이상하네요. 혹시 입력값을 trim해 주지 않아서 스페이스까지 포함된 닉네임을 검색하려고 하는 게 아닐까요? 만약 이런 문제라면 js에서 수정할 수 있을 것 같습니다.
  • profile profile
    일단 왜 그런지는 저는 알수 없지만 일정시간 후 동작하게 되는 것이 동작하려면 파이어폭스에서는 스페이스로 분리 한다음 다시 그 공백을 없애줘야 동작하는 것으로 보아 공백은 동작이 안되게 되어있는게 아닐까요... 닉네임에 공백은 안들어가니 제작자가 그렇게 처리를 했을라나요....
  • profile profile

    테스트를 해보니 공백도 입력하고 있는 것으로 인식 합니다 ㅋ

    웹지_기 라고 검색을 하면 웹지기가 검색되어지네요.

    그러니까 검색하고 스페이스를 한칸 띄운 상태에서도 커서가 아닌 상황이라 동일하게 동작을 하고 있지 않네요. 스페이스 이후 공백을 백스페이스로 없애주면 커서로 되면서 동작을 하게 되는거네요.

     

    근데 스페이스로 공백상태에서는 모습은 커서 모습으로 하고 있긴 하네요.

  • profile profile
    복잡하네요 ㅠ

    언제 기회가 있으면 모든 PC 및 모바일 브라우저에서 한글 입력을 처리하는 방식을 죄다 비교/분석해 봐야겠습니다. 예전에도 jQuery의 val()이 마지막으로 입력한 한글을 인식하지 못하는 문제를 본 적이 있는데, 그 때는 그냥 넘겼거든요...
  • profile profile
    모바일은 이 서비스 저희도 제공하지 않아요 ㅋ 동작하지 않죠 ㅋ