attribute - Guarde el texto de selección y muéstrelo más tarde en html y javascript
title html (8)
Necesitas capturar la ruta del nodo para conocer su ubicación.
Esto se puede hacer de varias maneras.
La forma más fácil es atravesar el domo hasta el cuerpo y crear un selector.
function getPathFromElement(element) {
var stack = [];
while (element.parentNode != document.documentElement) {
var sibCount = 0;
var sibIndex = 0;
var childNodes = element.parentNode.childNodes;
var childLength = childNodes.length;
for (var i = 0; i < childLength; i++) {
var sib = childNodes[i];
if (sib.nodeName == element.nodeName) {
if (sib === element) {
sibIndex = sibCount;
}
sibCount++;
}
}
if (element.hasAttribute("id") && element.id !== "") {
stack.unshift(`${element.nodeName.toLowerCase()}#${element.id}`);
}
else if (sibCount > 1) {
stack.unshift(`${element.nodeName.toLowerCase()}:eq(${sibIndex})`);
}
else {
stack.unshift(element.nodeName.toLowerCase());
}
element = element.parentNode;
}
return stack.join(" > ")
}
Supongamos que desea dar a sus usuarios dos opciones para seleccionar texto.
- Texto simple en la página.
- Selección de texto dentro de texto de entrada o área de texto.
Para la primera opción, puede usar un botón con el controlador de clic o el evento mouseup.
Usaré un botón para la simplicidad.
function sendDataToServer(data) {
}
document.querySelector("#button").addEventListener("click", function (e) {
var { target, text } = getSelectionTextAndContainerElement();
var path = getPathFromElement(target);
sendDataToServer({
path: path,
text: text
});
});
getSelectionTextAndContainerElement
función getSelectionTextAndContainerElement básicamente selecciona el texto y el elemento.
function getSelectionTextAndContainerElement() {
var text;
var containerElement = null;
if (typeof window.getSelection !== "undefined") {
var selection = window.getSelection();
if (selection.rangeCount) {
var node = selection.getRangeAt(0).commonAncestorContainer;
containerElement = node.nodeType == 1 ? node : node.parentNode;
text = selection.toString();
}
}
else if (typeof document.selection !== "undefined" && document.selection.type !== "Control") {
var textRange = document.selection.createRange();
containerElement = textRange.parentElement();
text = textRange.text;
}
return {
text: text,
target: containerElement
};
}
Para la segunda opción puede utilizar el controlador de eventos select
.
document.addEventListener("select", onSelect, false);
function onSelect(e) {
var { text } = getSelectionTextAndContainerElement();
var path = getPathFromElement(e.target);
sendDataToServer({
path: path,
text: text
});
}
Para texto de entrada o área de texto es mejor usar el controlador de eventos select
.
Si utilizará la primera opción para obtener la selección, no obtendrá el nodo de destino correcto debido al hecho de que el texto de entrada y el área de texto se crean utilizando Shadow DOM .
Por lo tanto, es mejor ignorar el nodo de destino generado por la función getSelectionTextAndContainerElement
y usar la propiedad de destino del evento select
.
He creado un ejemplo en jsfiddle para ti.
Tengo una situación difícil con html y javascript. Mi página html permite al usuario seleccionar texto y resaltarlo con colores. Ahora quiero guardar el estado en la base de datos para mostrarlo más tarde para ese usuario. Por supuesto, puedo guardar todo el HTML después de que el usuario lo haya editado. Pero SOLO solo quiero guardar algunos parámetros, combinar con el html original para mostrar la página en el estado que el usuario ve la última vez. Podemos utilizar esta función:
var index = innerHTML.indexOf(text);
para resaltar el texto en ese índice. Pero en caso de que haya muchos textos iguales en la página, quiero resaltar exactamente la palabra que el usuario resaltó antes.
¿Alguien puede enseñarme cómo lograr esto con javascript?
Aprecio mucho tu ayuda.
Primer ejemplo:
<textarea id="quote" cols="50" rows="5">
The above properties are especially useful in getting any user selected text from a form field where the indices of the selection isn''t already known. The following demo echoes what the user has selected from a TEXTAREA using these properties:
</textarea>
<div id="output"></div>
<script>
var quotearea = document.getElementById(''quote'')
var output = document.getElementById(''output'')
quotearea.addEventListener(''mouseup'', function(){
if (this.selectionStart != this.selectionEnd){ // check the user has selected some text inside field
var selectedtext = this.value.substring(this.selectionStart, this.selectionEnd)
output.innerHTML = selectedtext
}
}, false)
</script>
Segundo ejemplo
<head>
<script type="text/javascript">
function GetSelectedText () {
var selText = "";
if (window.getSelection) { // all browsers, except IE before version 9
if (document.activeElement &&
(document.activeElement.tagName.toLowerCase () == "textarea" ||
document.activeElement.tagName.toLowerCase () == "input"))
{
var text = document.activeElement.value;
selText = text.substring (document.activeElement.selectionStart,
document.activeElement.selectionEnd);
}
else {
var selRange = window.getSelection ();
selText = selRange.toString ();
}
}
else {
if (document.selection.createRange) { // Internet Explorer
var range = document.selection.createRange ();
selText = range.text;
}
}
if (selText !== "") {
alert (selText);
}
}
</script>
</head>
<body onmouseup="GetSelectedText ()">
Some text for selection.
<br /><br />
<textarea>Some text in a textarea element.</textarea>
<input type="text" value="Some text in an input field." size="40"/>
<br /><br />
Select some content on this page!
</body>
Tercer ejemplo:
<head>
<script type="text/javascript">
function GetSelection () {
var selection = "";
var textarea = document.getElementById("myArea");
if (''selectionStart'' in textarea) {
// check whether some text is selected in the textarea
if (textarea.selectionStart != textarea.selectionEnd) {
selection = textarea.value.substring (textarea.selectionStart, textarea.selectionEnd);
}
}
else { // Internet Explorer before version 9
// create a range from the current selection
var textRange = document.selection.createRange ();
// check whether the selection is within the textarea
var rangeParent = textRange.parentElement ();
if (rangeParent === textarea) {
selection = textRange.text;
}
}
if (selection == "") {
alert ("No text is selected.");
}
else {
alert ("The current selection is: " + selection);
}
}
</script>
</head>
<body>
<textarea id="myArea" spellcheck="false">Select some text within this field.</textarea>
<button onclick="GetSelection ()">Get the current selection</button>
</body>
Puede usar el método .serialize()
que devuelve una cadena de texto en notación estándar codificada en URL. ha seleccionado un elemento de formulario individual tal como <input>, <textarea>
etc..so enviar cadena de retorno serializada en DB usando $(form).serialize();
y para resaltar los cambios, marque Old $(form).serialize();
devuelva el valor con New $(form).serialize();
valor de retorno.
Puedes usar Array para guardar una selección del usuario !! Después de eso, guardas toda la matriz en tu base de datos. y cuando el usuario vuelve a ver el sitio, la función compara la letra y la palabra de la matriz y la resalta.
Ya que usa un complemento para resaltar texto, obtenga las palabras resaltadas usando jQuery:
var words = $(''.highlight'').map(function() { return $(this).text(); });
Luego póngalos en una matriz
var saved = [ ];
for (var word in words) {
if (-1 === saved.indexOf(word)) {
saved.push(word);
}
}
Finalmente puedes guardarlos en la base de datos. Una forma mala (pero rápida) de hacer esto es guardar la lista como delimitada por comas, un antipattern de SQL famoso:
var wordList = saved.join('','');
Cuando recupera el valor, lo divide en palabras y, por cada palabra, invoca el complemento de resaltado.
Esto no funcionará si alguno de los textos contiene una coma. En ese caso, es mejor que guardes cada palabra individualmente, lo que evita muchos otros problemas al final, en lugar de descubrir un carácter de separación que es "improbable" que aparezca en un texto de usuario.
desde una perspectiva de prueba, no hay manera de almacenar resaltados destacados si es posible alterar el html original sin ajustar también los resaltados.
Mi solución sería serializar todo el HTML de color. luego haga una función de limpieza para eliminar todos los resaltes de color y volver al html de línea de base. esto permite que el html en la base de datos incluya los resaltes de color y la edición todavía puede ocurrir con el resaltado conservado.
algo como:
function unhighlight() {
$(''.highlighted'').each(function(index, el) {
$(el).replaceWith($(el).html());
});
}
jsfiddle: https://jsfiddle.net/tobtedsc/5/
mi idea es agregar <span >
al principio y al final del texto seleccionado después de eso, cuando guarde el documento, todo el código html se guardará en la base de datos, de modo que cuando recupere el registro, el texto resaltado permanecerá.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>this is a paragraph creted to demonstrate highlighting selected text</p>
<script>
$(document).ready(function(){
$("p").on("mouseup",function() {
oldtxt = chosenText();
var newtxt = ''<span style="color:red;">'' + oldtxt +''</span>'';
$(this).html($(this).html().replace(oldtxt,newtxt));
});
//Grab selected text
function chosenText(){
if(window.getSelection){
return window.getSelection().toString();
}
else if(document.getSelection){
return document.getSelection();
}
else if(document.selection){
return document.selection.createRange().text;
}
}
});
</script>
Será cómodo en jQuery para agregar elementos.
Range
objetos Range
y document.execCommand
permiten manipular la selección con bastante facilidad. El principal problema en su caso es guardar el objeto de rango en un formato de texto.
Básicamente, lo que necesita es obtener startContainer
, startOffset
, endContainer
y endOffset
, que son los valores necesarios para crear objetos de rango. Offsets
son números, así que es bastante sencillo. Los contenedores son nodos, que no se pueden guardar directamente como cadenas, por lo que ese es el problema principal. Una cosa que puedes hacer es agregar claves a tu DOM y guardar la clave. Pero entonces, como en los contenedores de rangos hay nodos de texto, deberá guardar el índice del nodo de texto. Algo como esto debería permitir etiquetar el DOM con claves, usando una función recursiva:
function addKey(element) {
if (element.children.length > 0) {
Array.prototype.forEach.call(element.children, function(each, i) {
each.dataset.key = key++;
addKey(each)
});
}
};
addKey(document.body);
Una vez hecho esto, puede convertir objetos de rango en un objeto que puede guardar como una cadena. Me gusta esto:
function rangeToObj(range) {
return {
startKey: range.startContainer.parentNode.dataset.key,
startTextIndex: Array.prototype.indexOf.call(range.startContainer.parentNode.childNodes, range.startContainer),
endKey: range.endContainer.parentNode.dataset.key,
endTextIndex: Array.prototype.indexOf.call(range.endContainer.parentNode.childNodes, range.endContainer),
startOffset: range.startOffset,
endOffset: range.endOffset
}
}
Usando esto, puede guardar cada selección que el usuario crea en una matriz. Me gusta esto:
document.getElementById(''textToSelect'').addEventListener(''mouseup'', function(e) {
if (confirm(''highlight?'')) {
var range = document.getSelection().getRangeAt(0);
selectArray.push(rangeToObj(range));
document.execCommand(''hiliteColor'', false, ''yellow'')
}
});
Para guardar los puntos destacados, guarde cada objeto en JSON. Para probar esto, solo puede obtener la cadena JSON de su matriz de objetos de rango. Así (esto está usando el botón para obtener la selección en la parte superior):
document.getElementById(''getSelectionString'').addEventListener(''click'', function() {
alert(''Copy string to save selections: '' + JSON.stringify(selectArray));
});
Luego, cuando cargue el HTML vacío, puede usar una función inversa que creará rangos de los objetos que guardó en JSON. Me gusta esto:
function objToRange(rangeStr) {
range = document.createRange();
range.setStart(document.querySelector(''[data-key="'' + rangeStr.startKey + ''"]'').childNodes[rangeStr.startTextIndex], rangeStr.startOffset);
range.setEnd(document.querySelector(''[data-key="'' + rangeStr.endKey + ''"]'').childNodes[rangeStr.endTextIndex], rangeStr.endOffset);
return range;
}
Por lo tanto, podría tener una matriz de rangos en cadenas que convierte en objetos y luego convertirlos en objetos de Rango que puede agregar. Luego, usando execCommand, establece algún formato. De esta manera (esto está usando el botón de selección de ajustes en la parte superior, lo haces después de actualizar el violín):
document.getElementById(''setSelection'').addEventListener(''click'', function() {
var selStr = prompt(''Paste string'');
var selArr = JSON.parse(selStr);
var sel = getSelection();
selArr.forEach(function(each) {
sel.removeAllRanges();
sel.addRange(objToRange(each));
document.execCommand(''hiliteColor'', false, ''yellow'')
})
});
Consulte: https://jsfiddle.net/sek4tr2f/3/
Tenga en cuenta que hay casos en los que esto no funcionará; el principal problema es cuando el usuario selecciona contenido que ya está resaltado. Estos casos se pueden manejar, pero necesitará más condiciones.