본문 바로가기
WWWEB/Accessibility

[WAI-ARIA] auto complete 예제

by 미니토이 2020. 7. 17.


https://www.wah.or.kr:444/_Upload/pds2/WAI-ARIA%20%EC%82%AC%EB%A1%80%EC%A7%91(%EC%98%A8%EB%9D%BC%EC%9D%B8%ED%8C%90).pdf

=>  35p



https://developers.google.com/web/fundamentals/accessibility/semantics-aria/aria-labels-and-relationships?hl=ko




 요소

역할 

속성/상태 

설명 

<input> 

combobox 

 

콤보박스 역할을 정의 

<input>

 

aria-haspopup 

텍스트 필드와 연관된 하위 수준의 메뉴가 있으면 true, 그렇지 않으면 false 

<input> 

 

aira-autocomplete 

사용자 입력에 대한 자동완성 지원 여부를 설정 

<input> 

 

aira-activedescendant 

활성화 된 제안 목록으로 연결. 사용자 인터랙션에 따라 실시간으로 업데이트 

<input> 

 

aria-expanded 

펼침 상태 설정 

<div> 

status 

 

상태를 표시하는 역할 설정 

<div> 

 

aria-live 

실시간 알림 속성 설정 

<div> 

 

aria-relevant 

상태의 업데이트 알림 내용 설정 

<ul> 

listbox 

 

목록에서 하나 이상의 항목을 선택할 수 있는 역할로 설정 

<li> 

option 

 

선택 목록의 항목  





<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>auto complete ui</title>
</head>
<body>

    <form action="#" name="search" id="search" method="get">
        <fieldset id="autocomplete">
            <label class="hidden-accessible" for="keyword">검색어</label>
            <input type="text" name="keyword" id="keyword" required />
            <button type="submit">검색</button>
        </fieldset>
    </form>
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script>
        var $autocomplete = $'#autocomplete' ),
            // combobox로 설정할 input 요소를 참조
            $txtField = $autocomplete.find'input:text' ),
            // 추천 키워드 wrapper 요소 참조
            $suggestedWrap = $'<div />' ),
            // 상태 정보를 업데이트할 요소 참조
            $status = $'<div class="hidden-accessible" />' ),
            // 사용자의 키보드 내비게이팅 이전 값을 저장해 두기 위한 변수
            orgKeyword = '',
            // 사용자의 키 입력 중 수시로 추천 검색어를 가져오는 것을 방지하기 위한 타이머
            delayTimer = null;

        // WAI-ARIA Role, Property, State 초기화
        $txtField.attr({
            'role' : 'combobox',
            'aria-haspopup' : 'true',
            'aria-autocomplete' : 'list',
            'autocomplete' : 'off'
        });
        $suggestedWrap.appendTo$autocomplete );
        $status.attr({
            'role' : 'status',
            'aria-live' : 'polite',
            'aria-relevant' : 'additions' 
        }).appendTo$autocomplete );

        //$txtField 요소에 keyboard 이벤트 핸들러 바인딩
        $txtField.on({
            keyup : updateList,
            keydown : bindKeyEvent
        });

        /*
        * @Function updateList
        * @param {event} event
        */
        function updateList(event){
            event = event || window.event;
            event.stopImmediatePropagation();
            var keycode = event.which || event.keyCode;
            var keyword = $txtField.val();
            iforgKeyword === keyword ){
                return;
            }
            switchkeycode ){
                case 13 :
                case 27 :
                case 38 :
                case 40 :
                   event.preventDefault ? event.preventDefault() : event.returnValue = false;
                   break;
                default :
                    orgKeyword = keyword;
                    //일정 시간동안 키 입력이 없을 때 API 호출
                    clearTimeoutdelayTimer );
                    delayTimer = setTimeout(function(){
                        ifkeyword === '' ){
                            removeList();
                            return;
                        }
                        callAPIkeyword );
                    }, 400);
            }
        }

        /*
        * @function callAPI
        * @param {string} keyword
        */
        function callAPIkeyword ){
            $.ajax({
                url : 'https://dapi.kakao.com/v3/search/book',
                data : {
                    
                    output : 'json',
                    display : 15,
                    searchType : 'title',
                    sort : 'accu',
                    q : keyword
                },
                method : 'GET',
                dataType : 'jsonp',
                cache : false
            })
            .donefunctiondata ){
                // JSON 데이터 가공 (검색어로 쓸 데이터만 추출)
                for (var i = -1source = [], item = nullitem = data.channel.item[++i];){
                    source.push(
                        item['title'].replace( /\&lt;b\&gt;|\&lt;\/b\&gt;/g'' )
                    )
                }
                // 추출된 검색어 목록으로 검색 목록을 렌더링
                renderListsource );
            });
        }

        /*
        * @function renderList
        * @param {array} source
        */
        var $suggestedList = null;
        function renderListsource ){
            if$suggestedList === null ){
                // 추천 검색어 목록 생성
                $suggestedList = $'<ul class="listbox" />' );
                // 추천 검색어 목록 초기화
                // WAI-ARIA 적용. 이벤트 바인딩
                $suggestedList.attr({
                    'role' : 'listbox',
                    'data-count' : source.length
                })
                .appendTo$suggestedWrap )
                .on({
                    'mousedown' : functionevent ){
                        // 마우스로 선택 시 처리
                        event = event || window.event;
                        event.stopPropagation();
                        var activatedItem = $txtField.attr'aria-activedescendant' );
                        deSelectItem$('#' + activatedItem).index() );
                        selectItem$this ).index() );
                    }
                }, 'li');

                // 추천 검색어 목록 외 영역 클릭 시 초기화 처리
                $document ).on({
                   mousedown : functionevent ){
                       event = event || window.event;
                       ifevent.target === $txtfield[0] ){
                           return;
                       }
                       removeList();
                   } 
                });
            }

            // source로부터 추천 검색어 항목 생성
            var docFrag = document.createDocumentFragment();
            forvar i = -1item = nullitem = source[++i];){
                $'<li />' )
                    .attr({'id' : 'item' + i'role' : 'option'})
                    .textitem )
                    .appendTodocFrag );
            }
            $suggestedList
                .attr({
                    'data-count' : source.length
                })
                .empty()
                .appenddocFrag );
            
            // 상태정보 업데이트
            $txtField
                .removeAttr'aria-activedescendant' )
                .attr({
                    'aria-expaned' : 'true'
                });
            var state = $'<div />' ).textsource.length + '개의 추천 검색어가 있습니다.');
            $status.empth().appendstate );
        }

        /*
        * @function renderList
        * @param {array} source
        */
        function bindKeyEventevent ){
            event = event || window.event;
            event.stopImmediatePropagation();
            var keycode = event.keyCode || event.which,
                idx = 0,
                activatedItem = $txtField.attr'aria-activedescendant' );
            switchkeycode ){
                case 13 :   // enter
                    // 선택된 항목이 있는 경우
                    ifactivatedItem  !== undefined ){
                        event.preventDefault ? event.preventDefault() : event.returnValue = false;
                        $txtField.val$('#' + activatedItem).text() );
                        $txtFfield.parents'form' ).submit();
                    } else {
                        $txtField.parents'form' ).submit();
                    }
                    break;
                case 27 :   // ESC
                    event.preventDefault ? event.preventDefault() : event.returnValue = false;
                    $txtField.valorgKeyword );
                    removeList();
                    break;
                case 38 :   // up arrow key
                    event.preventDefault ? event.preventDefault() : event.returnValue = false;
                    if$suggestedList === null ){
                        return;
                    }
                    if$txtField.attr'aria-activedescendant' ) === undefined ){
                        idx = -1;
                    } else {
                        idx = $txtField
                                .attr'aria-activedescendant' )
                                .replace'item''' ) * 1 - 1;
                    }
                    deSelectItemidx + 1 );
                    selectItemidx );
                    break;
                case 40 :   // down arrow key
                    event.preventDefault ? event.preventdefault() : event.returnValue = false;
                    if$suggestedList === null ){
                        return;
                    }
                    if$txtField.attr'aaria-activedescendant' ) === undefined ){
                        orgKeyword = $txtField.val();
                        idx = 0;
                    } else {
                        idx = $txtField.attr'aria-activedescendant' )
                                    .replace'item''' ) * 1 + 1;
                    }
                    deSelectItemidx - 1 );
                    selectItemidx );
                    break;
            }
        }

        /*
        * @function selectItem
        * @param {number} idx the index number of Item that will be selected
        */
        function selectItemidx ){
            ifidx < 0 || $suggestedList === null || idx >= $suggestedList.data'count' ) ){
                $txtField.valorgKeyword );
                removeList();
                return;
            }
            var value = $suggestedList
                            .children'li:eq(' + idx + ')' )
                            .addClass'active' )
                            .text();
            $txtField
                .attr({
                    'aria-activedescendant' : 'item' + idx
                })
                .valvalue );
        }

        /*
        * @function renderList
        * @param {array} source
        */
        function deSelectItemidx ){
            $suggestedList.children'li:eq(' + idx + ')' ).removeClass'active' );
        }

        /*
        * @function removeList
        */
        function removeList(){
            if$suggestedList !== null ){
                $suggestedList.remove();
                $suggestedList = null;
                $txtField.removeAttr'aria-activedescendant' )
                    .attr({
                        'aria-expanded' : 'false'
                    });
                $status.empty();
            }
        }

    </script>
</body>
</html>


728x90
반응형

'WWWEB > Accessibility' 카테고리의 다른 글

[WAI-ARIA] radio button  (0) 2020.07.21
[WAI-ARIA] button  (0) 2020.07.21
[WAI-ARIA] multi form  (0) 2020.07.20
[WAI-ARIA] id/password input  (0) 2020.07.17
[WAI-ARIA] 탭 예제  (0) 2020.07.17

댓글