You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
En este capítulo cubriremos la selección en el documento, así como la selección en campos de formulario, como `<input>`.
10
10
11
-
JavaScript puede obtener la selección existente, seleccionar/deseleccionar tanto en su totalidad como parcialmente, eliminar la parte seleccionada del documento, envolverla en una etiqueta, etc.
11
+
JavaScript puede acceder una selección existente, seleccionar/deseleccionar nodos DOM tanto en su totalidad como parcialmente, eliminar la parte seleccionada del documento, envolverla en una etiqueta, etc.
12
12
13
-
Tu podrías usar ahora mismo las recetas que hay al final, En la sección "Resumen". Pero será mucho más beneficioso para ti si lees todo el capítulo. Los objetos subyacentes `Range` y `Selection` son fáciles de captar y, por lo tanto, no necesitará recetas para que hagan lo que deseas.
13
+
Puedes encontrar algunas recetas para tareas comunes al final del artículo, en la sección "Resumen". Pero será mucho más beneficiosa la lectura de todo el capítulo.
14
+
15
+
Los objetos subyacentes `Range` y `Selection` son fáciles de captar y no necesitarás recetas para que hagan lo que deseas.
14
16
15
17
## Range
16
18
17
19
El concepto básico de selección [Range](https://dom.spec.whatwg.org/#ranges), es básicamente un par de "puntos límite": inicio y fin del rango.
18
20
19
-
Cada punto es representado como un nodo DOM principal con el desplazamiento relativo desde su inicio. Si el nodo principal es un nodo de elemento, entonces el desplazamiento es un número secundario, para un nodo de texto es la posición en el texto. Ejemplos a continuación.
20
-
21
-
Seleccionemos algo.
22
-
23
-
Primero, podemos crear un rango (el constructor no tiene parámetros):
21
+
Un objeto rango se crea sin parámetros:
24
22
25
23
```js
26
24
let range =newRange();
27
25
```
28
26
29
27
Entonces podemos establecer los límites de selección usando `range.setStart(node, offset)` y `range.setEnd(node, offset)`.
30
28
31
-
Por ejemplo, considere este fragmento de HTML:
29
+
En adelante usaremos objetos `Range` para selección, pero primero creemos algunos de ellos.
30
+
31
+
### Seleccionando el texto parcialmente
32
+
33
+
Lo interesante es que el primer argumento `node` en ambos métodos puede ser tanto un nodo de texto o un nodo de elemento, y el significado del segundo argumento depende de ello.
34
+
35
+
**Si `node` es un nodo de texto, `offset` debe ser la posición en su texto.**
36
+
37
+
Por ejemplo, dado el elemento `<p>Hello</p>`, podemos crear el rango conteniendo las letras "ll":
38
+
39
+
```html run
40
+
<pid="p">Hello</p>
41
+
<script>
42
+
let range =newRange();
43
+
range.setStart(p.firstChild, 2);
44
+
range.setEnd(p.firstChild, 4);
45
+
46
+
// toString de un rango devuelve su contenido como un texto
47
+
console.log(range); // ll
48
+
</script>
49
+
```
50
+
51
+
Aquí tomamos el primer hijo de `<p>` (que es el nodo de texto) y especificamos la posición del texto dentro de él:
52
+
53
+

54
+
55
+
### Seleccionando nodos de elemento
56
+
57
+
**Alternativamente, si `node` es un nodo de elemento, `offset` debe ser el número de hijo.**
58
+
59
+
Esto es práctico para hacer rangos que contienen nodos como un todo, no detenerse en algún lugar dentro de su texto.
60
+
61
+
Por ejemplo, tenemos un fragmento de documento más complejo:
32
62
33
63
```html autorun
34
64
<pid="p">Example: <i>italic</i> and <b>bold</b></p>
35
65
```
36
66
37
-
Aquí está su estructura DOM, tenga en cuenta que aquí los nodos de texto son importantes para nosotros:
67
+
Aquí está su estructura DOM con ambos; nodos de texto y nodos de elemento:
Seleccionamos `"Example: <i>italic</i>"`. Son los dos primeros hijos de `<p>` (contando nodos de texto):
105
+
Hagamos un rango para `"Example: <i>italic</i>"`.
106
+
107
+
Como podemos ver, esta frase consiste de exactamente dos hijos de `<p>` con índices `0` y `1`:
76
108
77
109

78
110
79
-
-The starting point has `<p>`as the parent`node`, and`0`as the offset.
111
+
-El punto de inicio tiene `<p>`como nodo padre`node`, y`0`como offset.
80
112
81
-
So we can set it as`range.setStart(p, 0)`.
82
-
-The ending point also has`<p>`as the parent `node`, but `2`as the offset (it specifies the range up to, but not including`offset`).
113
+
Así que podemos establecerlo como`range.setStart(p, 0)`.
114
+
-El punto final también tiene`<p>`como nodo padre, but `2`como offset (especifica el rango "hasta", pero no incluyendo,`offset`).
83
115
84
-
So we can set it as`range.setEnd(p, 2)`.
116
+
Entonces podemos establecerlo como`range.setEnd(p, 2)`.
85
117
86
-
Here's the demo. If you run it, you can see that the text gets selected:
118
+
Aquí la demo. Si la ejeutas, puedes ver el texto siendo seleccionado::
87
119
88
120
```html run
89
121
<pid="p">Example: <i>italic</i> and <b>bold</b></p>
@@ -104,10 +136,7 @@ Here's the demo. If you run it, you can see that the text gets selected:
104
136
</script>
105
137
```
106
138
107
-
-`range.setStart(p, 0)` -- establece el comienzo en el hijo 0 de `<p>` (ese es el nodo de texto `"Example: "`).
108
-
-`range.setEnd(p, 2)` -- abarca el rango hasta (pero sin incluir) el segundo hijo de `<p>` (ese es el nodo de texto `" and "`, pero como el final no está incluido, el último nodo seleccionado es `<i>`).
109
-
110
-
Aquí hay un banco de pruebas más flexible en el que probar más variantes:
139
+
Aquí hay un banco de pruebas más flexible donde puedes establecer números de principio y fin y explorar otras variantes:
111
140
112
141
```html run autorun
113
142
<pid="p">Example: <i>italic</i> and <b>bold</b></p>
@@ -134,7 +163,9 @@ Ej. seleccionando de `1` a `4` da como rango `<i>italic</i> and <b>bold</b>`.
134
163
135
164

136
165
166
+
```smart header="Los nodos de inicio y final pueden ser diferentes"
137
167
No tenemos que usar el mismo nodo en `setStart` y `setEnd`. Un rango puede abarcar muchos nodos no relacionados. Solo es importante que el final sea posterior al comienzo.
168
+
```
138
169
139
170
### Seleccionar partes de nodos de texto
140
171
@@ -164,7 +195,13 @@ Necesitamos crear un rango, que:
164
195
</script>
165
196
```
166
197
167
-
El objeto de rango tiene las siguientes propiedades:
198
+
Como puedes ver, es fácil hacer un rango con lo que quieras.
199
+
200
+
Si queremos tomar los nodos como un todo, podemos pasar los elementos en `setStart/setEnd`. Si no, podemos trabajar en el nivel de texto.
201
+
202
+
## Propiedades de Range
203
+
204
+
El objeto rango que creamos arriba tiene las siguientes propiedades:
168
205
169
206

170
207
@@ -177,10 +214,13 @@ El objeto de rango tiene las siguientes propiedades:
177
214
-`commonAncestorContainer` -- el ancestro común más cercano de todos los nodos dentro del rango,
178
215
- en el ejemplo anterior: `<p>`
179
216
180
-
## Métodos de Range
217
+
218
+
## Métodos de selección de rango
181
219
182
220
Hay muchos métodos convenientes para manipular rangos.
183
221
222
+
Ya hemos visto `setStart` y `setEnd`, aquí hay otros métodos similares.
223
+
184
224
Establecer inicio de rango:
185
225
186
226
-`setStart(node, offset)` establecer inicio en: posición `offset` en `node`
@@ -193,15 +233,19 @@ Establecer fin de rango (métodos similares):
193
233
-`setEndBefore(node)` establecer final en: justo antes `node`
194
234
-`setEndAfter(node)` establecer final en: justo después `node`
195
235
196
-
**Como quedó demostrado, `node` puede ser un nodo de texto o de elemento: para nodos de texto `offset` omite esa cantidad de caracteres, mientras que para los nodos de elementos esa cantidad de nodos secundarios.**
236
+
Técnicamente, `setStart/setEnd` puede hacer cualquier cosa, pero más métodos brindan más conveniencia.
237
+
238
+
En todos estos métodos `node` puede ser un nodo de texto o de elemento: para nodos de texto `offset` salta esa cantidad de caracteres, mientras que para los nodos de elementos es la cantidad de nodos secundarios.**
197
239
198
-
Otros:
240
+
Más métodos aún para crear rangos:
199
241
-`selectNode(node)` establecer rango para seleccionar el `node`
200
242
-`selectNodeContents(node)` establecer rango para seleccionar todo el contenido de `node`
201
243
-`collapse(toStart)` si `toStart=true` establece final=comienzo, de otra manera comienzo=final, colapsando así el rango
202
244
-`cloneRange()` crea un nuevo rango con el mismo inicio/final
203
245
204
-
Para manipular el contenido dentro del rango:
246
+
## Métodos para edición en el rango:
247
+
248
+
Una vez creado el rango, podemos manipular su contenido usando estos métodos:
205
249
206
250
-`deleteContents()` -- eliminar el contenido de rango del documento
207
251
-`extractContents()` -- eliminar el contenido de rango del documento y lo retorna como [DocumentFragment](info:modifying-document#document-fragment)
@@ -213,7 +257,7 @@ Con estos métodos podemos hacer básicamente cualquier cosa con los nodos selec
213
257
214
258
Aquí está el banco de pruebas para verlos en acción:
215
259
216
-
```html run autorun height=260
260
+
```html run refresh autorun height=260
217
261
Haga clic en los botones para ejecutar métodos en la selección, "resetExample" para restablecerla.
218
262
219
263
<pid="p">Example: <i>italic</i> and <b>bold</b></p>
@@ -268,25 +312,35 @@ Haga clic en los botones para ejecutar métodos en la selección, "resetExample"
268
312
</script>
269
313
```
270
314
271
-
También existen métodos para comparar rangos, pero rara vez se utilizan. Cuando los necesite, consulte el [spec](https://dom.spec.whatwg.org/#interface-range) o [MDN manual](https://developer.mozilla.org/es/docs/Web/API/Range).
315
+
También existen métodos para comparar rangos, pero rara vez se utilizan. Cuando los necesite, consulte el [spec](https://dom.spec.whatwg.org/#interface-range) o [manual MDN](https://developer.mozilla.org/es/docs/Web/API/Range).
272
316
273
317
274
318
## Selection
275
319
276
-
`Range` es un objeto genérico para gestionar rangos de selección. Podemos crear tales objetos, pasarlos alrededor -- no seleccionan visualmente nada por sí mismos.
320
+
`Range` es un objeto genérico para gestionar rangos de selección. Pero crearlos no significa que podamos ver la selección en la pantalla.
277
321
278
-
La selección de documentos está representada por el objeto `Selection`, que se puede obtener como `window.getSelection()` o `document.getSelection()`.
322
+
Podemos crear objetos `Range`, pasarlos; no seleccionan nada visualmente por sí mismos.
279
323
280
-
Una selección puede incluir cero o más rangos. Al menos, el [Selection API specification](https://www.w3.org/TR/selection-api/) lo dice. Sin embargo, en la práctica, solo Firefox permite seleccionar múltiples rangos en el documento usando `key:Ctrl+click` (`key:Cmd+click` para Mac).
324
+
La selección de documento está representada por el objeto `Selection`, que se puede obtener como `window.getSelection()` o `document.getSelection()`Una selección puede incluir cero o más rangos. Al menos, la [especificación Selection API](https://www.w3.org/TR/selection-api/) lo dice. Sin embargo, en la práctica, solo Firefox permite seleccionar múltiples rangos en el documento usando `key:Ctrl+click` (`key:Cmd+click` para Mac).
281
325
282
-
Aquí hay una captura de pantalla de una selección con 3 rangos, realizada en Firefox:
326
+
Aquí hay una captura de pantalla de una selección con 3 rangos en Firefox:
283
327
284
328

285
329
286
330
Otros navegadores admiten un rango máximo de 1. Como veremos, algunos de los métodos de `Selection` implica que puede haber muchos rangos, pero nuevamente, en todos los navegadores excepto Firefox, hay un máximo de 1.
287
331
332
+
Aquí hay una pequeña demo que muestra la selección actual (selecciona algo y haz clic) como texto:
Como dijimos antes, una selección en teoría tiene múltiples rangos. Podemos obtener estos objetos rango usando el método:
339
+
340
+
-`getRangeAt(i)` -- obtiene el rango "i" comenzando desde `0`. En todos los navegadores excepto Firefox, solo `0` es usado.
341
+
342
+
También existen propiedades que a menudo brindan conveniencia.
343
+
290
344
Similar a Range, una selección tiene un inicio, llamado "ancla(anchor)", y un final, llamado "foco(focus)".
291
345
292
346
Las principales propiedades de selection son:
@@ -298,23 +352,26 @@ Las principales propiedades de selection son:
298
352
-`isCollapsed` -- `true` si la selección no selecciona nada (rango vacío), o no existe.
299
353
-`rangeCount` -- recuento de rangos en la selección, máximo "1" en todos los navegadores excepto Firefox.
300
354
301
-
````smart header="El final de la selección puede estar en el documento antes del inicio"
302
-
Hay muchas formas de seleccionar el contenido, dependiendo del agente de usuario: mouse, teclas de acceso rápido, toques en un móvil, etc.
355
+
```smart header="Inicio/final, Selection vs. Range"
356
+
357
+
Hay una diferencia importante entre anchor/focus (ancla/foco) de una selección comparado al inicio/fin de un rango.
303
358
304
-
Algunos de ellos, como un mouse, permiten que se pueda crear la misma selección en dos direcciones: "de izquierda a derecha" y "de derecha a izquierda".
359
+
Sabemos que los objetos `Range` siempre tienen el inicio antes que el final.
305
360
306
-
Si el inicio (ancla) de la selección va en el documento antes del final (foco), se dice que esta selección tiene una dirección "hacia adelante".
361
+
En las selecciones, no siempre es así.
362
+
363
+
Seleccionar algo con el ratón puede hacerse en ambas direcciones: tanto de izquierda a derecha como de deracha a izquierda.
364
+
365
+
Cuando el botón es presionado, cuando se mueve hacia adelante en el documento, entonces su final (foco) estará después del inicio (ancla).
307
366
308
367
Ej. si el usuario comienza a seleccionar con el mouse y pasa de "Example" a "italic":
309
368
310
369

311
370
312
-
De lo contrario, si van desde el final de "italic" to "Example", la selección se dirige "hacia atrás", su foco estará antes del ancla:
371
+
...Pero la selección puede hacerse hacia atrás: comenzando por "italic" terminando en "Example", su foco estará antes del ancla:
313
372
314
373

315
-
316
-
Eso es diferente de los objetos `Range` que siempre se dirigen hacia adelante: el inicio del rango no puede ser posterior a su final.
317
-
````
374
+
```
318
375
319
376
## Eventos Selection
320
377
@@ -339,20 +396,21 @@ From <input id="from" disabled> – To <input id="to" disabled>
339
396
340
397
let {anchorNode, anchorOffset, focusNode, focusOffset} = selection;
341
398
342
-
// anchorNode and focusNode are text nodes usually
399
+
// anchorNode y focusNode usualmente son nodos de texto
Hay dos enfoques para la copia de contenido seleccionado:
350
409
351
-
Para obtener toda la selección:
352
-
- Como texto: solo llama `document.getSelection().toString()`.
353
-
- Como nodos DOM: obtenga los rangos subyacentes y llame a su método `cloneContents()` (solo el primer rango si no admitimos la selección múltiple de Firefox).
410
+
1. Podemos usar `document.getSelection().toString()` para obtenerlo como texto.
411
+
2.O copiar el DOM entero, por ejemplo si necesitamos mantener el formato, podemos obtener los rangos correspondientes con `getRangesAt(...)`. Un objeto `Range`, a su vez, tiene el método `cloneContents()` que clona su contenido y devuelve un objeto `DocumentFragment`, que podemos insertar en algún otro lugar.
354
412
355
-
Y aquí está la demostración de cómo obtener la selección como texto y como nodos DOM:
413
+
Aquí está la demostración de cómo obtener la selección como texto y como nodos DOM:
356
414
357
415
```html run height=100
358
416
<p id="p">Select me: <i>italic</i> and <b>bold</b></p>
@@ -388,7 +446,7 @@ Métodos de selección para agregar/eliminar rangos:
388
446
-`removeAllRanges()`--elimina todos los rangos.
389
447
-`empty()`-- alias para `removeAllRanges`.
390
448
391
-
Además, existen métodos convenientes para manipular el rango de selección directamente, sin `Range`:
449
+
Además, existen métodos convenientes para manipular el rango de selección directamente, sin llamadas intermedias a `Range`:
392
450
393
451
-`collapse(node, offset)`-- Reemplazar el rango seleccionado con uno nuevo que comienza y termina en el `node` dado, en posición `offset`.
394
452
-`setPosition(node, offset)`-- alias para `collapse`.
0 commit comments