Skip to content

Commit 3adc340

Browse files
Next/Previous feature (#7)
* update deps * Add previous/next feature * documentation * Build and bump * Travis
1 parent b824a58 commit 3adc340

9 files changed

+246
-94
lines changed

.travis.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
sudo: required
1+
os:
2+
- linux
23
dist: trusty
34
language: node_js
45
node_js:

README.md

+33-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ Adds "Ctrl+F" find box to highlight text in the DOM
1717
findInNw.initialize();
1818
</script>
1919
```
20-
1. Use `CTRL+F` and `ESC` to show/hide the search box
20+
1. Use `CTRL+F` to display and give focus to the search box
21+
1. After typing, press `ENTER` to go to highlight/scroll to the next match.
22+
1. Use `TAB` to navigate to the "previous", "next", and "close" buttons.
23+
1. Use `ENTER` or `SPACE` to activate a button when focused.
24+
1. User `ESC` to hide the search box and return focus to the body
2125

2226

2327

@@ -45,6 +49,11 @@ This is used to programmitcally hide the search box. `ESC` will still hide it to
4549
This is used to programmitcally find text.
4650

4751

52+
### `findInNw.highlightNext();` and `findInNw.highlightPrevious();`
53+
54+
This will highlight and scroll to the next or previous match.
55+
56+
4857
### `findInNw.clearTokens();`
4958

5059
This is used to remove all the highlighted tokens.
@@ -57,12 +66,22 @@ This is used to remove all the highlighted tokens.
5766

5867
### Highlight tokens
5968

60-
All highlight tokens of matching searched text will be wrapped in a `<mark class="find-in-nw-token">searched text</mark>`. You can customize this by targeting the following
69+
All highlight tokens of matching searched text will be wrapped in a `<mark class="find-in-nw-token">searched text</mark>`.
70+
71+
They will also contain a `data-find-in-nw-position="4"` data attribute, the number correlates to a zero-based index of all matches.
72+
73+
As you navigate from one match to the next, the currently selected match will have a class of `.find-in-nw-current-token`.
74+
75+
You can customize this by targeting the following
6176

6277
```css
6378
mark.find-in-nw-token {
6479
background-color: #00F;
6580
}
81+
82+
mark.find-in-nw-current-token {
83+
background-color: #38D878;
84+
}
6685
```
6786

6887

@@ -77,10 +96,20 @@ Each element of the search box is styled by targeting a class. They also all hav
7796
/* The input field you type in */
7897
#find-in-nw-input {}
7998

80-
/* The count of matching highlighted items */
99+
/* The current selected match number. Ex: The number 1 in "1/5" */
100+
#find-in-nw-current {}
101+
102+
/* The separator between the current and count. Ex: The slash (/) in "1/5" */
103+
#find-in-nw-of {}
104+
105+
/* The count of matching highlighted items. Ex: The number 5 in "1/5" */
81106
#find-in-nw-count {}
82107

83-
/* The X close button */
108+
/* The previous and next buttons, ∧ and ∨ */
109+
#find-in-nw-previous {}
110+
#find-in-nw-next {}
111+
112+
/* The × close button */
84113
#find-in-nw-close {}
85114
```
86115

dev.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@
8484

8585
Quisque vel semper orci. Praesent sit amet tempor dolor. Sed eu ipsum vel justo maximus cursus nec sed orci. Nullam sagittis urna enim, eget egestas leo pretium quis. Etiam leo justo, semper vitae erat at, commodo vulputate massa. Suspendisse non gravida velit. Morbi commodo dignissim lacus, id laoreet risus. Vestibulum aliquam dapibus turpis quis pharetra. Ut eget ullamcorper magna. Donec et volutpat enim, a elementum lectus. Maecenas a porta turpis, nec venenatis odio. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
8686

87-
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque mi justo, dapibus eget risus at, dignissim eleifend neque. Pellentesque consequat lacus nec quam auctor, vel euismod arcu pharetra. Duis eget hendrerit justo. Nam sit amet lectus gravida, auctor diam eu, dapibus mauris. Mauris facilisis sapien commodo odio pulvinar, quis venenatis sapien posuere. Aenean nec egestas ipsum. Suspendisse cursus sed elit id consectetur. Fusce volutpat porta odio sed convallis. Proin faucibus sed felis vitae commodo. Suspendisse consequat eget mi ut accumsan. Nulla fermentum ligula eget tempus fermentum. Ut vel libero mollis, consequat ligula non, posuere ante. Etiam diam massa, tempus ut dignissim at, ultrices non urna.
87+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque mi justo, dapibus eget risus at, dignissim eleifend neque. Pellentesque consequat lacus nec quam auctor, vel euismod arcu pharetra. Duis eget hendrerit justo. Nam sit amet lectus gravida, auctor diam eu, dapibus mauris. Mauris dolore facilisis sapien commodo odio pulvinar, quis venenatis sapien posuere. Aenean nec egestas ipsum. Suspendisse cursus sed elit id consectetur. Fusce volutpat porta odio sed convallis. Proin faucibus sed felis vitae commodo. Suspendisse consequat eget mi ut accumsan. Nulla fermentum ligula eget tempus fermentum. Ut vel libero mollis, consequat ligula non, posuere ante. Etiam diam massa, tempus ut dignissim at, ultrices non urna.
8888

8989
Pellentesque luctus rutrum enim, ac euismod lacus fermentum vel. In egestas non massa eget mollis. Mauris auctor vitae neque in lacinia. Donec lorem est, eleifend ut ipsum eu, euismod laoreet justo. Maecenas id viverra quam, nec ullamcorper enim. Duis turpis nisl, laoreet vitae dui ac, elementum aliquet nisl. Vivamus gravida sodales volutpat. Donec aliquet massa id interdum eleifend. Maecenas eu egestas lectus, nec venenatis tortor. Suspendisse vel rutrum ligula. Maecenas blandit tincidunt dolor, vel imperdiet ligula semper ullamcorper. Maecenas a lectus elit. Integer a quam ornare, sollicitudin risus at, finibus mi.
9090

dist/find-in-nw.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

find-in-nw.gif

62.2 KB
Loading

package.json

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "findinnw",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Simulate the Ctrl+F (find) feature from Chrome in NW.js",
55
"main": "test.html",
66
"scripts": {
@@ -21,14 +21,14 @@
2121
"author": "",
2222
"license": "MIT",
2323
"devDependencies": {
24-
"eslint": "^6.6.0",
24+
"eslint": "^6.8.0",
2525
"eslint-config-tjw-base": "^1.0.0",
2626
"findandreplacedomtext": "^0.4.6",
27-
"node-sass": "^4.13.0",
27+
"node-sass": "^4.13.1",
2828
"nw": "sdk",
29-
"sass": "^1.23.1",
29+
"sass": "^1.26.3",
3030
"sass-lint": "^1.13.1",
31-
"terser": "^4.3.9",
31+
"terser": "^4.6.11",
3232
"tjw-sasslint-rules": "^2.1.0"
3333
},
3434
"repository": "https://github.com/nwutils/find-in-nw"

src/index.js

+137-29
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
const findInNw = {
33
initialized: false,
44
lastSearched: '',
5+
total: 0,
6+
currentToken: 0,
7+
dataAttribute: 'data-find-in-nw-position',
8+
9+
resetState: function () {
10+
this.lastSearched = '';
11+
this.total = 0;
12+
this.currentToken = 0;
13+
},
514

615
create: {
716
css: '/* PLACEHOLDER */',
@@ -27,42 +36,36 @@ const findInNw = {
2736

2837
return input;
2938
},
30-
count: function () {
31-
const count = document.createElement('span');
32-
count.setAttribute('id', 'find-in-nw-count');
33-
count.setAttribute('class', 'find-in-nw-count');
34-
count.innerHTML = '0';
35-
36-
return count;
37-
},
38-
close: function () {
39-
const button = document.createElement('button');
40-
button.setAttribute('id', 'find-in-nw-close');
41-
button.setAttribute('class', 'find-in-nw-close');
42-
button.innerHTML = '&times;';
39+
element: function (el, id, value) {
40+
const element = document.createElement(el);
41+
element.setAttribute('id', 'find-in-nw-' + id);
42+
element.setAttribute('class', 'find-in-nw-' + id);
43+
element.innerHTML = value + '';
4344

44-
return button;
45+
return element;
4546
},
4647

4748
composeSearchBox: function () {
4849
const container = this.container();
49-
const input = this.input();
50-
const count = this.count();
51-
const close = this.close();
5250

53-
container.appendChild(input);
54-
container.appendChild(count);
55-
container.appendChild(close);
51+
container.appendChild(this.input());
52+
container.appendChild(this.element('span', 'current', 0));
53+
container.appendChild(this.element('span', 'of', '/'));
54+
container.appendChild(this.element('span', 'count', 0));
55+
container.appendChild(this.element('button', 'previous', '&and;'));
56+
container.appendChild(this.element('button', 'next', '&or;'));
57+
container.appendChild(this.element('button', 'close', '&times;'));
5658

5759
return container;
5860
}
5961
},
6062

61-
closeButtonClicked: function () {
62-
const close = document.getElementById('find-in-nw-close');
63-
close.addEventListener('click', function (evt) {
64-
evt.preventDefault();
65-
this.hideSearchBox();
63+
keyDownPressed: function () {
64+
const input = document.getElementById('find-in-nw-input');
65+
input.addEventListener('keydown', function (evt) {
66+
if (evt.key === 'Enter') {
67+
this.highlightNext();
68+
}
6669
}.bind(this));
6770
},
6871
inputChanged: function () {
@@ -77,10 +80,34 @@ const findInNw = {
7780
}
7881
}.bind(this));
7982
},
83+
previousButtonClicked: function () {
84+
const previous = document.getElementById('find-in-nw-previous');
85+
previous.addEventListener('click', function (evt) {
86+
evt.preventDefault();
87+
this.highlightPrevious();
88+
}.bind(this));
89+
},
90+
nextButtonClicked: function () {
91+
const next = document.getElementById('find-in-nw-next');
92+
next.addEventListener('click', function (evt) {
93+
evt.preventDefault();
94+
this.highlightNext();
95+
}.bind(this));
96+
},
97+
closeButtonClicked: function () {
98+
const close = document.getElementById('find-in-nw-close');
99+
close.addEventListener('click', function (evt) {
100+
evt.preventDefault();
101+
this.hideSearchBox();
102+
}.bind(this));
103+
},
80104

81105
eventBinding: function () {
82-
this.closeButtonClicked();
106+
this.keyDownPressed();
83107
this.inputChanged();
108+
this.previousButtonClicked();
109+
this.nextButtonClicked();
110+
this.closeButtonClicked();
84111
},
85112
keyBindings: function () {
86113
document.onkeydown = function (pressed) {
@@ -98,6 +125,23 @@ const findInNw = {
98125
}.bind(this);
99126
},
100127

128+
highlightPrevious: function () {
129+
this.currentToken = this.currentToken - 1;
130+
if (this.currentToken < 0) {
131+
this.currentToken = (this.total - 1);
132+
}
133+
this.updateCount();
134+
this.highlightCurrentToken();
135+
},
136+
highlightNext: function () {
137+
this.currentToken = this.currentToken + 1;
138+
if (this.currentToken > (this.total - 1)) {
139+
this.currentToken = 0;
140+
}
141+
this.updateCount();
142+
this.highlightCurrentToken();
143+
},
144+
101145
showSearchBox: function () {
102146
const searchBox = document.getElementById('find-in-nw-search-box');
103147
const input = document.getElementById('find-in-nw-input');
@@ -129,10 +173,72 @@ const findInNw = {
129173
return elements;
130174
},
131175

132-
updateCount: function () {
176+
setDataPositionAttribute: function () {
177+
let index = 0;
178+
let searchLength = this.lastSearched.length;
179+
let tempLength = searchLength;
180+
133181
const tokens = document.getElementsByClassName('find-in-nw-token');
182+
183+
[...tokens].forEach(function (token) {
184+
let tokenLength = token.innerText.length;
185+
token.setAttribute(this.dataAttribute, index);
186+
187+
if (tokenLength === searchLength) {
188+
index = index + 1;
189+
tempLength = searchLength;
190+
} else {
191+
tempLength = tempLength - tokenLength;
192+
if (tempLength < 1) {
193+
index = index + 1;
194+
tempLength = searchLength;
195+
}
196+
}
197+
}.bind(this));
198+
199+
if (!tokens) {
200+
index = 0;
201+
}
202+
this.total = index;
203+
},
204+
highlightCurrentToken: function () {
205+
const currentTokenClass = 'find-in-nw-current-token';
206+
207+
let previousTokens = document.getElementsByClassName(currentTokenClass);
208+
let currentTokens = document.querySelectorAll('.find-in-nw-token[' + this.dataAttribute + '="' + this.currentToken + '"]');
209+
210+
if (previousTokens && previousTokens.length) {
211+
previousTokens = [...previousTokens];
212+
previousTokens.forEach(function (token) {
213+
token.classList.remove(currentTokenClass);
214+
});
215+
}
216+
217+
if (currentTokens && currentTokens.length) {
218+
currentTokens = [...currentTokens];
219+
currentTokens.forEach(function (token) {
220+
token.classList.add(currentTokenClass);
221+
});
222+
223+
currentTokens[0].scrollIntoView({
224+
behavior: 'auto',
225+
block: 'center',
226+
inline: 'center'
227+
});
228+
}
229+
},
230+
231+
updateCount: function () {
232+
const current = document.getElementById('find-in-nw-current');
134233
const count = document.getElementById('find-in-nw-count');
135-
count.innerHTML = tokens.length.toLocaleString();
234+
235+
let currentValue = 0;
236+
if (this.total !== 0) {
237+
currentValue = this.currentToken + 1;
238+
}
239+
240+
current.innerHTML = (currentValue).toLocaleString();
241+
count.innerHTML = this.total.toLocaleString();
136242
},
137243
clearTokens: function () {
138244
const tokens = document.getElementsByClassName('find-in-nw-token');
@@ -149,7 +255,7 @@ const findInNw = {
149255
element.normalize();
150256
});
151257

152-
this.lastSearched = '';
258+
this.resetState();
153259
this.updateCount();
154260
},
155261
search: function (text) {
@@ -165,7 +271,9 @@ const findInNw = {
165271
});
166272

167273
this.lastSearched = text;
274+
this.setDataPositionAttribute();
168275
this.updateCount();
276+
this.highlightCurrentToken();
169277
},
170278
initialize: function () {
171279
if (!this.initialized) {

0 commit comments

Comments
 (0)