Доступный образец перетаскивания не работает

Я создал образец перетаскивания, используя эту ссылку. В этом примере пользователь может перетащить любой элемент из первой строки и поместить его в любой второй элемент строки. При отбрасывании перетаскиваемого элемента целевой объект удаляется. Пользователь может выбрать элемент, используя пробел, и может перетащить его во второй ряд, используя клавишу ввода. Я протестировал свое приложение, используя jaws и nvda, после выбора любого элемента фокус не перемещался на следующую строку, тогда как без этих программ чтения с экрана образец работает нормально. После адресной строки фокус направляется непосредственно на второй элемент первого ряда, а не на первый элемент.

(function () {

    //exclude older browsers by the features we need them to support
    //and legacy opera explicitly so we don't waste time on a dead browser
    if (!document.querySelectorAll ||
        !('draggable' in document.createElement('span')) ||
        window.opera
    ) {
        return;
    }

    //get the collection of draggable targets and add their draggable attribute
    for (var targets = document.querySelectorAll('[data-draggable="target"]'),
            len = targets.length,
            i = 0; i < len; i++) {
        targets[i].setAttribute('aria-dropeffect', 'none');
    }

    //get the collection of draggable items and add their draggable attributes
    for (var
            items = document.querySelectorAll('[data-draggable="item"]'),
            len = items.length,
            i = 0; i < len; i++) {
        items[i].setAttribute('draggable', 'true');
        items[i].setAttribute('aria-grabbed', 'false');
        items[i].setAttribute('tabindex', '0');
    }



    //dictionary for storing the selections data 
    //comprising an array of the currently selected items 
    //a reference to the selected items' owning container
    //and a refernce to the current drop target container
    var selections = {
        items: null,
        owner: null,
        droptarget: null
    };

    //function for selecting an item
    function addSelection(item) {
        //if the owner reference is still null, set it to this item's parent
        //so that further selection is only allowed within the same container
        if (!selections.owner) {
            selections.owner = item.parentNode;
        }

        //or if that's already happened then compare it with this item's parent
        //and if they're not the same container, return to prevent selection
        else if (selections.owner != item.parentNode) {
            return;
        }

        //set this item's grabbed state
        item.setAttribute('aria-grabbed', 'true');

        for (var
                items = document.querySelectorAll('[data-draggable="item"][aria-grabbed="false"]'),
                len = items.length,
                i = 0; i < len; i++) {
            items[i].removeAttribute('draggable');
            items[i].removeAttribute('aria-grabbed');
            items[i].removeAttribute('tabindex');
        }

        //add it to the items array
        selections.items = item;
    }

    //function for unselecting an item
    function removeSelection(item) {
        //reset this item's grabbed state
        item.setAttribute('aria-grabbed', 'false');

        //then find and remove this item from the existing items array
        //        for (var len = selections.items.length, i = 0; i < len; i++) {
        //            if (selections.items[i] == item) {
        //                selections.items.splice(i, 1);
        //                break;
        //            }
        //        }
        selections.items = null;
    }

    //function for resetting all selections
    function clearSelections() {
        //if we have any selected items
        if (selections.items) {
            //reset the owner reference
            selections.owner = null;

            //reset the grabbed state on every selected item
            //            for (var len = selections.items.length, i = 0; i < len; i++) {
            //                selections.items[i].setAttribute('aria-grabbed', 'false');
            //            }
            selections.items.setAttribute('aria-grabbed', 'false');

            //then reset the items array  
            selections.items = null;
        }
    }

    //shorctut function for testing whether a selection modifier is pressed
    function hasModifier(e) {
        return (e.ctrlKey || e.metaKey || e.shiftKey);
    }


    //function for applying dropeffect to the target containers
    function addDropeffects() {
        //apply aria-dropeffect and tabindex to all targets apart from the owner

        for (var len = targets.length, i = 0; i < len; i++) {
            if (
                targets[i] != selections.owner &&
                targets[i].getAttribute('aria-dropeffect') == 'none'
            ) {
                targets[i].setAttribute('aria-dropeffect', 'move');
                targets[i].setAttribute('tabindex', '0');
            }
        }

        //remove aria-grabbed and tabindex from all items inside those containers
        for (var len = items.length, i = 0; i < len; i++) {
            if (
                items[i].parentNode != selections.owner &&
                items[i].getAttribute('aria-grabbed')
            ) {
                items[i].removeAttribute('aria-grabbed');
                items[i].removeAttribute('tabindex');
            }
        }
    }

    //function for removing dropeffect from the target containers
    function clearDropeffects() {
        //if we have any selected items
        if (selections.items) {
            //reset aria-dropeffect and remove tabindex from all targets
            for (var len = targets.length, i = 0; i < len; i++) {
                if (targets[i].getAttribute('aria-dropeffect') != 'none') {
                    targets[i].setAttribute('aria-dropeffect', 'none');
                    targets[i].removeAttribute('tabindex');
                }
            }

            //restore aria-grabbed and tabindex to all selectable items 
            //without changing the grabbed value of any existing selected items
            for (var len = items.length, i = 0; i < len; i++) {
                if (!items[i].getAttribute('aria-grabbed') && items[i].getAttribute('draggable') == 'true') {
                    items[i].setAttribute('aria-grabbed', 'false');
                    items[i].setAttribute('tabindex', '0');
                } else if (items[i].getAttribute('aria-grabbed') == 'true') {
                    items[i].setAttribute('tabindex', '0');
                }
            }
        }
    }

    //shortcut function for identifying an event element's target container
    function getContainer(element) {
        do {
            if (element.nodeType == 1 && element.getAttribute('aria-dropeffect')) {
                return element;
            }
        }
        while (element = element.parentNode);

        return null;
    }



    //mousedown event to implement single selection
    document.addEventListener('mousedown', function (e) {
        //if the element is a draggable item
        if (e.target.getAttribute('draggable')) {
            //clear dropeffect from the target containers
            clearDropeffects();

            //if the multiple selection modifier is not pressed 
            //and the item's grabbed state is currently false
            if (!hasModifier(e) &&
                e.target.getAttribute('aria-grabbed') == 'false'
            ) {
                //clear all existing selections
                clearSelections();

                //then add this new selection
                addSelection(e.target);
            }
        }

        //else [if the element is anything else]
        //and the selection modifier is not pressed 
        else if (!hasModifier(e)) {
            //clear dropeffect from the target containers
            clearDropeffects();

            //clear all existing selections
            clearSelections();
        }

        //else [if the element is anything else and the modifier is pressed]
        else {
            //clear dropeffect from the target containers
            clearDropeffects();
        }

    }, false);

    //mouseup event to implement multiple selection
    document.addEventListener('mouseup', function (e) {
        //if the element is a draggable item 
        //and the multipler selection modifier is pressed
        if (e.target.getAttribute('draggable') && hasModifier(e)) {
            //if the item's grabbed state is currently true
            if (e.target.getAttribute('aria-grabbed') == 'true') {
                //unselect this item
                removeSelection(e.target);

                //if that was the only selected item
                //then reset the owner container reference
                if (!selections.items) {
                    selections.owner = null;
                }
            }

            //else [if the item's grabbed state is false]
            else {
                //add this additional selection
                addSelection(e.target);
            }
        }

    }, false);

    //dragstart event to initiate mouse dragging
    document.addEventListener('dragstart', function (e) {
        //if the element's parent is not the owner, then block this event
        if (selections.owner != e.target.parentNode) {
            e.preventDefault();
            return;
        }

        //[else] if the multiple selection modifier is pressed 
        //and the item's grabbed state is currently false
        if (
            hasModifier(e) &&
            e.target.getAttribute('aria-grabbed') == 'false'
        ) {
            //add this additional selection
            addSelection(e.target);
        }

        //we don't need the transfer data, but we have to define something
        //otherwise the drop action won't work at all in firefox
        //most browsers support the proper mime-type syntax, eg. "text/plain"
        //but we have to use this incorrect syntax for the benefit of IE10+
        e.dataTransfer.setData('text', '');

        //apply dropeffect to the target containers
        addDropeffects();

    }, false);



    //keydown event to implement selection and abort
    document.addEventListener('keydown', function (e) {
        //if the element is a grabbable item 
        if (e.target.getAttribute('aria-grabbed')) {
            //Space is the selection or unselection keystroke
            if (e.keyCode == 32) {
                //if the multiple selection modifier is pressed 
                if (hasModifier(e)) {

                    ////alert("278");
                    //if the item's grabbed state is currently true
                    if (e.target.getAttribute('aria-grabbed') == 'true') {
                        //if this is the only selected item, clear dropeffect 
                        //from the target containers, which we must do first
                        //in case subsequent unselection sets owner to null
                        ////alert("284");
                        if (selections.items) {
                            clearDropeffects();
                        }

                        //unselect this item
                        removeSelection(e.target);

                        //if we have any selections
                        //apply dropeffect to the target containers, 
                        //in case earlier selections were made by mouse
                        if (selections.items) {
                            addDropeffects();
                        }

                        //if that was the only selected item
                        //then reset the owner container reference
                        if (!selections.items) {
                            selections.owner = null;
                        }
                    }

                    //else [if its grabbed state is currently false]
                    else {
                        ////alert("308");
                        //add this additional selection
                        addSelection(e.target);

                        //apply dropeffect to the target containers 
                        addDropeffects();
                    }
                }

                //else [if the multiple selection modifier is not pressed]
                //and the item's grabbed state is currently false
                else if (e.target.getAttribute('aria-grabbed') == 'false') {
                    //alert("320");
                    //clear dropeffect from the target containers
                    clearDropeffects();

                    //clear all existing selections
                    clearSelections();

                    //add this new selection
                    addSelection(e.target);

                    //apply dropeffect to the target containers
                    addDropeffects();
                }

                //else [if modifier is not pressed and grabbed is already true]
                else {
                    //alert("336");
                    //apply dropeffect to the target containers 
                    addDropeffects();
                }

                //then prevent default to avoid any conflict with native actions
                e.preventDefault();
            }

            //Modifier + M is the end-of-selection keystroke
            if (e.keyCode == 77 && hasModifier(e)) {
                //if we have any selected items
                if (selections.items) {
                    //apply dropeffect to the target containers 
                    //in case earlier selections were made by mouse
                    addDropeffects();

                    //if the owner container is the last one, focus the first one
                    if (selections.owner == targets[targets.length - 1]) {
                        targets[0].focus();
                    }

                    //else [if it's not the last one], find and focus the next one
                    else {
                        for (var len = targets.length, i = 0; i < len; i++) {
                            if (selections.owner == targets[i]) {
                                targets[i + 1].focus();
                                break;
                            }
                        }
                    }
                }

                //then prevent default to avoid any conflict with native actions
                e.preventDefault();
            }
        }

        //Escape is the abort keystroke (for any target element)
        if (e.keyCode == 27) {
            //if we have any selected items
            if (selections.items) {
                //clear dropeffect from the target containers
                clearDropeffects();

                //then set focus back on the last item that was selected, which is 
                //necessary because we've removed tabindex from the current focus
                //>>
                //selections.items[selections.items.length - 1].focus();

                //clear all existing selections
                clearSelections();

                //but don't prevent default so that native actions can still occur
            }
        }

    }, false);



    //related variable is needed to maintain a reference to the 
    //dragleave's relatedTarget, since it doesn't have e.relatedTarget
    var related = null;

    //dragenter event to set that variable
    document.addEventListener('dragenter', function (e) {
        related = e.target;

    }, false);

    //dragleave event to maintain target highlighting using that variable
    document.addEventListener('dragleave', function (e) {
        //get a drop target reference from the relatedTarget
        var droptarget = getContainer(related);

        //if the target is the owner then it's not a valid drop target
        if (droptarget == selections.owner) {
            droptarget = null;
        }

        //if the drop target is different from the last stored reference
        //(or we have one of those references but not the other one)
        if (droptarget != selections.droptarget) {
            //if we have a saved reference, clear its existing dragover class
            if (selections.droptarget) {
                selections.droptarget.className =
                    selections.droptarget.className.replace(/ dragover/g, '');
            }

            //apply the dragover class to the new drop target reference
            if (droptarget) {
                droptarget.className += ' dragover';
            }

            //then save that reference for next time
            selections.droptarget = droptarget;
        }

    }, false);

    //dragover event to allow the drag by preventing its default
    document.addEventListener('dragover', function (e) {
        //if we have any selected items, allow them to be dragged
        if (selections.items) {
            e.preventDefault();
        }

    }, false);



    //dragend event to implement items being validly dropped into targets,
    //or invalidly dropped elsewhere, and to clean-up the interface either way
    document.addEventListener('dragend', function (e) {
        //if we have a valid drop target reference
        //(which implies that we have some selected items)
        if (selections.droptarget) {
            //append the selected items to the end of the target container
            //            for (var len = selections.items.length, i = 0; i < len; i++) {
            //                selections.droptarget.appendChild(selections.items[i]);
            //            }

            //selections.droptarget.appendChild(selections.items);

            selections.items.removeAttribute("data-draggable");
            selections.items.setAttribute('draggable', 'false');
            selections.items.removeAttribute('aria-grabbed');
            selections.items.setAttribute('tabindex', '-1');

            selections.droptarget.parentNode.insertBefore(selections.items, selections.droptarget.nextElementSibling)
            selections.droptarget.parentNode.removeChild(selections.droptarget);

            for (var
                    items = document.querySelectorAll('[data-draggable="item"]'),
                    len = items.length,
                    i = 0; i < len; i++) {
                items[i].setAttribute('draggable', 'true');
                items[i].setAttribute('aria-grabbed', 'false');
                items[i].setAttribute('tabindex', '0');
            }
            //selections.droptarget = selections.items;
            //prevent default to allow the action   
            e.preventDefault();
        }

        //if we have any selected items
        if (selections.items) {
            //clear dropeffect from the target containers
            clearDropeffects();

            //if we have a valid drop target reference
            if (selections.droptarget) {
                //reset the selections array
                clearSelections();

                //reset the target's dragover class
                selections.droptarget.className =
                    selections.droptarget.className.replace(/ dragover/g, '');

                //reset the target reference
                selections.droptarget = null;
            }
        }

    }, false);



    //keydown event to implement items being dropped into targets
    document.addEventListener('keydown', function (e) {;
        //if the element is a drop target container
        if (e.target.getAttribute('aria-dropeffect')) {
            //Enter or Modifier + M is the drop keystroke
            if (e.keyCode == 13 || (e.keyCode == 77 && hasModifier(e))) {
                //append the selected items to the end of the target container

                // e.target.appendChild(selections.items);

                selections.items.removeAttribute("data-draggable");
                selections.items.setAttribute('draggable', 'false');
                selections.items.removeAttribute('aria-grabbed');
                selections.items.setAttribute('tabindex', '-1');

                e.target.parentNode.insertBefore(selections.items, e.target.nextElementSibling);
                e.target.parentNode.removeChild(e.target);


                for (var
                        items = document.querySelectorAll('[data-draggable="item"]'),
                        len = items.length, i = 0; i < len; i++) {
                    items[i].setAttribute('draggable', 'true');
                    items[i].setAttribute('aria-grabbed', 'false');
                    items[i].setAttribute('tabindex', '0');
                }
                //e.target = selections.items;
                //clear dropeffect from the target containers

                clearDropeffects();

                //then set focus back on the last item that was selected, which is 
                //necessary because we've removed tabindex from the current focus

                //>> 
                //selections.items[selections.items.length - 1].focus();

                //reset the selections array
                clearSelections();

                //prevent default to to avoid any conflict with native actions
                e.preventDefault();
            }
        }

    }, false);

})();
* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}
.boxes {
    float: left;
    width: 100px;
    height: 35px;
    margin: 10px;
    padding: 10px;
    border: 1px solid black;
}
.clearfix {
    content: '';
    display: block;
    clear: both;
}
img {
    display: inline-block;
    width: 100px;
    margin: 10px;
    vertical-align: top;
}

/* drop target state */

[data-draggable="target"][aria-dropeffect="move"] {
    border-color: #68b;
    background: #fff;
}

/* drop target focus and dragover state */

[data-draggable="target"][aria-dropeffect="move"]:focus,
[data-draggable="target"][aria-dropeffect="move"].dragover {
    outline: none;
    box-shadow: 0 0 0 1px #fff, 0 0 0 3px #68b;
}

/* draggable items */

img {
    display: inline-block;
    width: 100px;
    margin: 10px;
}

/* items focus state */

[data-draggable="item"]:focus {
    outline: none;
    box-shadow: 0 0 0 2px #68b, inset 0 0 0 1px #ddd;
}

/* items grabbed state */

[data-draggable="item"][aria-grabbed="true"] {
    border: 5px solid #8ad;
    color: #fff;
}
<body>
    <div>
        <img src="images/41.png" alt="img1" data-draggable="item" role="img">
        <img src="images/165.png" alt="img2" data-draggable="item" role="img">
        <img src="images/135.png" alt="img3" data-draggable="item" role="img">
        <img src="images/155.png" alt="img4" data-draggable="item" role="img">
    </div>
    <div>
        <img src="images/img5.png" alt="img5" data-draggable="target" role="img">
        <img src="images/img6.png" alt="img6" data-draggable="target" role="img">
        <img src="images/img7.png" alt="img7" data-draggable="target" role="img">
        <img src="images/img8.png" alt="img8" data-draggable="target" role="img">
    </div>
    <div>
        <h2 id="kbdinstructions">Keyboard Instructions</h2>
        <ol class="instructions">
            <li>Use the <b>Tab</b> to move across images.</li>
            <li>Select the item you want using <b>Spacebar</b>.</li>
            <li>Use the <b>Tab</b> again to move across images.</li>
            <li>Press <b>Enter</b> to move selected image to the target image.</li>
        </ol>
    </div>
</body>

Почему это происходит?

0 ответов

Другие вопросы по тегам