Skip to content

Commit f635386

Browse files
Documentation
1 parent c1e9d15 commit f635386

File tree

2 files changed

+67
-11
lines changed

2 files changed

+67
-11
lines changed

README.md

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
# purescript-textcursor
2-
An isomorphic `TextCursor` type for selections in DOM elements (`<input>` and `<textarea>`). Provides shared DOM methods and TextCursor manipulations.
2+
An `TextCursor` isomorphism for selections in DOM elements (`<input>` and `<textarea>`). Provides shared DOM methods and TextCursor manipulations.
33

4-
## Supported elements
5-
All `<textarea>` elements and `<input>` elements with the `type` attribute set to one of the following:
6-
- input (default)
7-
- email
8-
- search
9-
- url
4+
## The problem
5+
In the DOM, selections within input elements are represented by a starting and ending index, and the value of the element. If the value is changed, the selection is reset, so the user loses their place in the field. The selection can be added back to the element, but accurately predicting the indices is near impossible with complex operations. This library provides a sane way of dealing with selections.
106

11-
## TextCursor
7+
## The solution: TextCursor
128
A `TextCursor` is defined as the following type:
139
```purescript
1410
newtype TextCursor = TextCursor
@@ -20,6 +16,66 @@ newtype TextCursor = TextCursor
2016

2117
It represents a selection in an element in three regions: the text `before` the cursor/selection, the text inside the `selection` (empty if there is just a cursor), and the text `after`.
2218

23-
What this does is allow transformations to occur (such as replacements, white-space simplification) while preserving the relative location of the cursor or selection.
19+
This allows transformations to occur (such as replacements, white-space simplification) while preserving the relative location of the cursor or selection.
20+
21+
A simple replacement that matches on single characters in each field of a `TextCursor` will have the same content as replacing the entire string, but it will also preserve the locations of the cursor or selection within the field:
22+
23+
```purescript
24+
replacement = toUpper
25+
tc = TextCursor
26+
{ before: "Hello, "
27+
, selected: "World"
28+
, after: "! Hi!"
29+
}
30+
tcreplaced = over _all replacement tc
31+
content tcreplaced == replacement (content tc)
32+
```
33+
34+
Note that certain transformations will depend on the position of the text cursor or selection within the field, particularly if they rely on matching a string of characters versus single characters. For example, a replacement `s/''/"/g` depends on two characters being adjacent and will not match if the cursor or edge of a selection lies in between the two single quotes. But for a simple case like this, checks can be added to handle edge cases, if desired:
2435

25-
Note that certain transformations will depend on the position of the text cursor or selection within the field, particularly if they rely on a string of characters versus single characters (e.g. a replacement ` ``|'' -> "`, which depends on quote characters being adjacent, as opposed to `[A-Z] -> [a-z]`, which does not care where the cursor falls as it selects a single character without context).
36+
```purescript
37+
q = "'"
38+
q2 = q <> q
39+
qq = "\""
40+
replaceQuote = replaceAll (wrap q2) (wrap qq)
41+
replaceLast s =
42+
case stripSuffix (wrap q) of
43+
Nothing -> s
44+
Just s' -> s' <> qq
45+
-- left biased for quotes matched across an edge
46+
stitch left right
47+
| endsWith q left
48+
&& startsWith q right
49+
= Tuple (replaceLast left) (drop 1 right)
50+
| otherwise = Tuple left right
51+
replaceAcross left right =
52+
stitch (replaceQuote left) right
53+
<#> replaceQuote
54+
replaceQuotes = case _ of
55+
TextCursor { before, selected: "", after } ->
56+
let
57+
Tuple before' after' =
58+
replaceAcross before after
59+
in TextCursor
60+
{ before: before'
61+
, selected: ""
62+
, after: after'
63+
}
64+
TextCursor { before, selected, after } ->
65+
let
66+
Tuple before' (Tuple selected' after') =
67+
replaceAcross before selected
68+
<#> flip replaceAcross after
69+
in TextCursor
70+
{ before: before'
71+
, selected: selected'
72+
, after: after'
73+
}
74+
```
75+
76+
## Supported DOM elements
77+
All `<textarea>` elements and `<input>` elements with the `type` attribute set to one of the following:
78+
- input (default)
79+
- email
80+
- search
81+
- url

test/Properties.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import DOM.Util.TextCursor
55
import Data.Array (concat)
66
import Data.String as S
77
import Data.Traversable (for_)
8-
import Prelude (Unit, discard, flip, map, ($), (+), (<#>), (<$>), (<*>), (>>=), (>>>))
8+
import Prelude (Unit, discard, flip, map, ($), (+), (<#>), (<$>), (>>=), (>>>))
99
import Test.QuickCheck (QC, Result, arbitrary, quickCheck, (<?>), (===))
1010
import Test.QuickCheck.Gen (Gen)
1111

0 commit comments

Comments
 (0)