Cómo editar un enlace dentro de un div de contentEditable

¿Alguien tiene alguna sugerencia sobre cómo editar un enlace en un contentEditable div? Sería ideal que, una vez que se hace clic con el mouse en el enlace, o que el cursor toca el enlace, que aparezca un pequeño mensaje emergente y que el usuario pueda cambiar la propiedad href del enlace. El mensaje no es el problema, pero ¿cómo es posible detectar que se ha hecho clic en el enlace o que el cursor ha llegado al enlace? onfocus no parece funcionar en una división de contentEditable en Firefox y Safari. ¿Algunas ideas?

Estoy bastante seguro de que esto es lo que estabas buscando, sin embargo, utilicé jQuery solo para hacer que el concepto sea un poco más fácil de burlar. Vista previa jsbin disponible, así que ve a verlo. Si alguien puede convertir esto en JS puro por el bien de la respuesta, lo he convertido en una wiki comunitaria.

Funciona vinculando los eventos keyup / click en el div editable, luego verificando el nodo en el que se ubica a los usuarios usando window.getSelection() para los estándares, o document.selection para esas personas IE. El rest del código maneja el estallido / manejo de las ediciones.

jQuery métodos:

 function getSelectionStartNode(){ var node,selection; if (window.getSelection) { // FF3.6, Safari4, Chrome5 (DOM Standards) selection = getSelection(); node = selection.anchorNode; } if (!node && document.selection) { // IE selection = document.selection var range = selection.getRangeAt ? selection.getRangeAt(0) : selection.createRange(); node = range.commonAncestorContainer ? range.commonAncestorContainer : range.parentElement ? range.parentElement() : range.item(0); } if (node) { return (node.nodeName == "#text" ? node.parentNode : node); } } $(function() { $("#editLink").hide(); $("#myEditable").bind('keyup click', function(e) { var $node = $(getSelectionStartNode()); if ($node.is('a')) { $("#editLink").css({ top: $node.offset().top - $('#editLink').height() - 5, left: $node.offset().left }).show().data('node', $node); $("#linktext").val($node.text()); $("#linkhref").val($node.attr('href')); $("#linkpreview").attr('href', $node.attr('href')); } else { $("#editLink").hide(); } }); $("#linktext").bind('keyup change', function() { var $node = $("#editLink").data('node'); $node.text($(this).val()); }); $("#linkhref").bind('keyup change', function() { var $node = $("#editLink").data('node'); $node.attr('href', $(this).val()); $node.and('#linkpreview').attr('href',$(this).val()); }); }); 

Lo probé solo en cromo

estilo de botón

 button.cmd { ... } 

botón de la barra de herramientas

  

diálogo modal -> editor de enlaces

  

javascript, jquery

 var cur_range; var cur_dialog; $(document).ready(function() { $('.editor').focus(); //on toolbar button mousedown keep current range $('.cmd').mousedown(function(event) { event.preventDefault(); try { cur_range = document.getSelection().getRangeAt(0); } catch(error) { console.log(error); } }); $('#linkEditor').click(function() { event.preventDefault(); //if user select edit link, else insert link if (!cur_range.collapsed) { //if selection is a link set edit values if (cur_range.commonAncestorContainer.parentNode.nodeName.toLowerCase() == 'a') { $('#linkUrl').val(cur_range.commonAncestorContainer.parentNode.href); $('#linkData').val(cur_range.commonAncestorContainer.data); } else { //alert here return false; } } else { $('#linkUrl').val(''); $('#linkData').val(''); } //open link editor dialog $('#optionDialog').show(); $('#linkOption').show(); //store current dialog section (link, table, header) cur_dialog = $('#linkOption'); }); $('#linkDone').click(function() { event.preventDefault(); if (cur_range.collapsed) { //insert link at caret position var node = '' + $('#linkData').val() + ''; cur_range.insertNode(cur_range.createContextualFragment(node)); } else { //replace existing link values cur_node = cur_range.commonAncestorContainer.parentNode; cur_node.href = $('#linkUrl').val(); cur_node.innerText = $('#linkData').val(); } //update range document.getSelection().removeAllRanges(); document.getSelection().addRange(cur_range); document.getSelection().collapseToEnd(); $('.modal-close').click(); //if you don't use observer some code is nedeed //save_history(1); }); //When the user clicks anywhere outside of the modal, close it window.onclick = function(event) { optionDialog = document.getElementById('optionDialog'); if (event.target == optionDialog) { $('#optionDialog').hide(); cur_dialog.hide(); cur_dialog = null; } } });