开发者

HTML5,draggable and contentEditable not working together

When a draggable attribute is enabled on a parent element(<li>) I cant make contenteditable work on its child 开发者_StackOverflow社区element (<a>).

The focus goes on to child element (<a>),but I cant edit it at all.

Please check this sample

http://jsfiddle.net/pavank/4rdpV/11/

EDIT: I can edit content when I disable draggable on <li>


I came across the same problem today, and found a solution [using jQuery]

$('body').delegate('[contenteditable=true]','focus',function(){
    $(this).parents('[draggable=true]')
            .attr('data-draggableDisabled',1)
            .removeAttr('draggable');
    $(this).blur(function(){
        $(this).parents('[data-draggableDisabled="1"]')
                .attr('draggable','true')
                .removeAttr('data-draggableDisabled');
    });
});

$('body') can be replaced by anything more specific.

If new contenteditable elements are not added in the runtime, one can use bind instead of delegate.


It makes sense that the draggable and contenteditable properties would collide. contenteditable elements, like any text field, will focus on mousedown (not click). draggable elements operate based on mousemove, but so does selecting text in a contenteditable element, so how would the browser determine whether you are trying to drag the element or select text? Since the properties can't coexist on the same element, it appears that you need a javascript solution.

Try adding these two attributes to your anchor tag:

onfocus="this.parentNode.draggable = false;"
onblur="this.parentNode.draggable = true;"

That works for me if I add it to the <a> tags in your jsFiddle. You could also use jQuery if it's more complicated than getting the parentNode.


Note: This is a workaround since I believe the inability for these two functionalities to work together resides in the HTML spec itself (i.e. the not working together thing is intentional since the browser can't determine whether you want to focus or drag on the mousedown event)


I noticed you explicitly set 'no libraries', so I will provide a raw javascript/HTML5 answer

http://jsfiddle.net/4rdpV/26/

This was my crack at it.

First of all, it might be better to include the data in one single localStorage item, rather than scatter it.

storage={
    '1.text':'test 1',
    '2.text':'test 2'
}
if(localStorage['test']){
    storage=JSON.parse(localStorage['test'])
}

this creates that ability, using JSON to convert between object and string. Objects can indeed be nested

I also added (edit) links next to the items, when clicked, these links will transform the items into input elements, so you can edit the text. After hitting enter, it transforms it back and saves the data. At the same time, the list items remain draggable.

After saving, hit F12 in chrome, find the console, and look in the localStorage object, you will see all the data was saved in localStorage['test'] as an Object using JSON.stringify()

I tried my best to design this to be scaleable, and I think I succeeded well enough; you just need to replace the HTML with a container and use a javascript for loop to write out several items, using the iterator of your choice to fill the parameter for edit(). For example:

Say you changed storage to hold "paradigms" of lists, and you have one called "shopping list". And say the storage object looks something like this:

{
    "shopping list":{
         1:"Milk",
         2:"Eggs",
         3:"Bread"
    }
}

This could render that list out:

for(i in storage['shopping list']){
    _item = storage['shopping list'][i];
    container.innerHTML+='<li draggable=true><a id="item'+i+'">'+_item+'</a><a href="#" onclick="edit('+i+')"> (edit)</a></li>'
}

Of course, if you were to edit the structure of the storage object, you would need to edit the functions as well.

The output would look something like this:

Milk (edit)
Eggs (edit)
Bread (edit)

Don't worry about the input elements if that worries you; CSS can easily fix it to look like it didn't just change.

If you don't want the (edit) links to be visible, for example, you can do this in CSS:

a[href="#"]{
    display:none;
}
li[draggable="true"]:hover a[href="#"]{
    display:inline;
}

Now the edit links will only appear when you hover the mouse over the list item, like this version:

http://jsfiddle.net/4rdpV/27/


I hope this answer helped.


Using html5sortable and newer JQuery events (delegate is deprecated, answer 3 years after initial question), bug still affects Chrome 37. Contenteditable spans and html5sortable seem to play nice in other browsers. I know this is only partially relevant, just keeping documentation on changes I've noticed.

$(document).on('focus', 'li span[contenteditable]', function() {
    $(this).parent().parent().sortable('destroy'); // removes sortable from the whole parent UL
});

$(document).on('blur', 'li span[contenteditable]', function() {
    $(this).parent().parent().sortable({ connectWith: '.sortable' }); // re-adds sortable to the parent UL
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜