Skip to content

Commit

Permalink
api cleanup. See #13
Browse files Browse the repository at this point in the history
  • Loading branch information
padolsey committed Sep 28, 2013
1 parent e7bccc4 commit 190a054
Show file tree
Hide file tree
Showing 4 changed files with 779 additions and 393 deletions.
32 changes: 14 additions & 18 deletions demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,13 @@ <h3>This text is all randomly sized so you can have a go at matching "across ele
var container = document.getElementById('container');
var warning = document.getElementById('warning');
var input = document.getElementById('find');
var isInit = false;

var colors = ['red', 'green', 'blue', 'purple', '#E67A00'];

var instance;
var inputHandler = function() {
isInit && findAndReplaceDOMText.revert();
instance && instance.revert();
warning.style.display = 'none';
if (input.value) {
isInit = true;
var called = false;
try {
var regex = RegExp(input.value, 'gi');
Expand All @@ -67,17 +65,16 @@ <h3>This text is all randomly sized so you can have a go at matching "across ele
return;
}
try {
findAndReplaceDOMText(
regex,
container,
function(fill, matchIndex) {
instance = findAndReplaceDOMText(container, {
find: regex,
replace: function(portion, match) {
called = true;
var el = document.createElement('em');
el.style.backgroundColor = colors[matchIndex%colors.length];
el.innerHTML = fill;
el.style.backgroundColor = colors[match.index % colors.length];
el.innerHTML = portion.text;
return el;
}
);
});
} catch(e) {
warning.innerHTML = 'Error: ' + e;
warning.style.display = 'inline';
Expand All @@ -99,18 +96,17 @@ <h3>This text is all randomly sized so you can have a go at matching "across ele
};

// Initial replacement to make words different sizes
findAndReplaceDOMText(
/\w+/g,
container,
function(fill, matchIndex) {
findAndReplaceDOMText(container, {
find: /\w+/g,
replace: function(portion) {
var el = document.createElement('span');
el.style.fontSize = (Math.random() + .6) + 'em';
el.innerHTML = fill;
el.innerHTML = portion.text;
return el;
}
);
});

input.value = '\\w+';
input.value = '.....';
input.onkeyup();


Expand Down
89 changes: 61 additions & 28 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,89 +1,122 @@
# findAndReplaceDOMText

**[See the demo](http://padolsey.github.com/findAndReplaceDOMText/demo.html)**

`findAndReplaceDOMText` searches for regular expression matches in a DOM node and wraps all matches (and portions of matches separated by node bounderies) with a specified element.
`findAndReplaceDOMText` searches for regular expression matches in a given DOM node and replaces or wraps each match with a node or piece of text that you can specify.

For example:

```html
<p id="t">
123 456 999
123 456 Hello
</p>
```

```js
findAndReplaceDOMText(/9+/, document.getElementById('t'), 'em');
findAndReplaceDOMText(document.getElementById('t'), {
find: /Hello/,
wrap: 'em'
});
```

This would result in:

```html
<p id="t">
123 456 <em>999</em>
123 456 <em>Hello</em>
</p>
```

And it also works when matches are spread **across multiple nodes**! E.g.

```html
<p id="t">
123 456 99<span>9 foo</span>
123 456 Hell<span>o Goodbye</span>
</p>
```

```js
findAndReplaceDOMText(/9+/, document.getElementById('t'), 'em');
findAndReplaceDOMText(document.getElementById('t'), {
find: /Hello/,
wrap: 'em'
});
```

This would result in:

```html
<p id="t">
123 456 <em>99</em><span><em>9</em> foo</span>
123 456 <em>Hell</em><span><em>o</em> Goodbye</span>
</p>
```

The `EM` element has been added twice, to cover both portions of the match.

### Documentation
## API

It's pretty simple. `findAndReplaceDOMText` has the following argument signature:
`findAndReplaceDOMText` has the following argument signature:

```js
findAndReplaceDOMText(
regex, // (RegExp) The regular expression to match
element, // (Element) The element to search within
replacement, // (String|Node|Function) Explained below
captureGroup, // (Number) OPTIONAL: The regex capture group to replace
elementFilter // (Function) OPTIONAL: A function to filter elements to process
element, // (Element) The element or text-node to search within
options // (Object) Explained below
);
```
### API: Options

The third argument (`replacement`) can be one of:
The `options` object includes:

* A nodeName (e.g. `"em"` or `"span"`)
* A "stencil" node that will be cloned.
* A function which will return an element whenever called with a match portion (text)
* **find** (`RegExp | String`): Something to search for.
* **replace** *optional* (`String | Function`): A String of text to replace matches with, or a Function which should return replacement Node or String. If you use a string, it can contain various tokens:
* `$n` to represent the *n*th captured group of a regular expression (i.e. `$1`, `$2`, ...)
* `$0` or `$&` to represent the entire match
* <code>$`</code> to represent everything to the left of the match.
* `$'` to represent everything to the right of the match.
* **wrap** *optional* (`String | Node`): A string representing the node-name of an element that will be wrapped around matches (e.g. `span` or `em`). Or a Node (i.e. a stencil node) that we will clone for each match portion.
* **portionMode** *optional* (`String`, one of `"retain"` or `"first"`): Indicates whether to re-use existing node boundaries when replacing a match with text (i.e. the default, `"retain"`), or whether to instead place the entire replacement in the first-found match portion's node. *Most of the time you'll want the default*.
* **filterElements** *optional* (`Function`): A function to be called on every element encountered by `findAndReplaceDOMText`. If the function returns false the element will be altogether ignored.

E.g. if I wanted to replace every instance of `foo` in an element with `<span class="found">` I would simply do:
#### What is a portion?

```js
var span = document.createElement('span');
span.className = 'found';
findAndReplaceDOMText(/foo/g, myElement, span);
A portion or "match portion" is a part of a match that is delimited by node boundaries. Not all matches occur within a single text-node, so `findAndReplaceDOMText` has to be able to deal with cross-boundary matches (e.g. when matching `/foo/` in `"<em>f</em>oo"`).

#### The `replace` Function

If you pass a function to the `replace` option your function will be called on every portion of every match and is expected to return a DOM Node (a Text or Element node). Your function will be passed both the portion and the encapsulating match of that portion.

E.g.

*Input HTML*

```html
<div id="container">
Explaining how to write a replace <em>fun</em>ction
</div>
```

To avoid certain elements (e.g. Style and Script tags) you can specify an element filter like so:
*JS*

```js
findAndReplaceDOMText(/foo/g, myElement, 'span', null, function(el) {
var name = el.nodeName.toLowerCase();
return name !== 'style' && name !== 'script';
findAndReplaceDOMText(document.getElementById('container'), {
find: 'function',
replace: function(portion, match) {
return '[[' + portion.index + ']]';
}
});
```

*Output HTML*

```html
<div id="container">
Explaining how to write a replace <em>[[0]]</em>[[1]]
</div>
```

### Changelog

* 0.4.0 (28 Sept 2013): Major API overhaul, including a new arg signature (`findAndReplaceDOMText(node, options)`, plus the ability to replace a match with text or wrap it with a DOM Node.
* 0.3.0: Switch to semver, add node-filtering feature (as requested in [Issue #11](https://github.com/padolsey/findAndReplaceDOMText/issues/11)
* 0.2: Fix case where regular expression contains word bounderies and add support for specifying a capture group to replace as the fourth argument to `findAndReplaceDOMText()` (see [issue #5](https://github.com/padolsey/findAndReplaceDOMText/issues/5))
* 0.11: Minor fix: Make sure replacement node function is called in order of matches (see [issue #4](https://github.com/padolsey/findAndReplaceDOMText/issues/4))
* 0.1: Initial commit + Fix for IE's broken HTML5 cloneNode ([pull request](https://github.com/padolsey/findAndReplaceDOMText/pull/3))
* 0.1: Initial commit + Fix for IE's broken HTML5 cloneNode ([pull request](https://github.com/padolsey/findAndReplaceDOMText/pull/3))
Loading

0 comments on commit 190a054

Please sign in to comment.