govuk_tech_docs 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile +2 -0
- data/docs/configuration.md +8 -0
- data/example/config/tech-docs.yml +2 -0
- data/govuk_tech_docs.gemspec +2 -0
- data/lib/assets/javascripts/_analytics.js +15 -0
- data/lib/assets/javascripts/_modules/search.js +198 -0
- data/lib/assets/javascripts/_start-modules.js +2 -0
- data/lib/assets/javascripts/_vendor/jquery.mark.js +1081 -0
- data/lib/assets/stylesheets/_core.scss +1 -0
- data/lib/assets/stylesheets/modules/_search.scss +137 -0
- data/lib/assets/stylesheets/modules/_technical-documentation.scss +4 -0
- data/lib/govuk_tech_docs.rb +13 -0
- data/lib/govuk_tech_docs/version.rb +1 -1
- data/lib/source/images/search-result-caret.svg +13 -0
- data/lib/source/layouts/_search.erb +16 -0
- data/lib/source/layouts/core.erb +1 -0
- metadata +21 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0b627893fa39ba6cc6484a977b7b9c00639ad28
|
4
|
+
data.tar.gz: a45ebcff76937b949bb5c7388359bbd26cbe1d53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fe4b821226d40bff2fd3d2eff34887862e74eda39c00ef058f512b448f995d1d0181aff90e3448c5493108dbae2eb76d5ee34746a5c7077adb4fede3107c3553
|
7
|
+
data.tar.gz: b9e34c88cfc72c46f4cab5e73bd3946e4475e6a1a3a42f2140ef8fb024f48f57ef6f8e57a8f1dc5b47aef41a9ccf7f07bb7ce080d6cb7f81a806da52d5ee8881
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.5.0
|
4
|
+
|
5
|
+
### New feature: Search
|
6
|
+
|
7
|
+
Adds search functionality. This indexes pages only and is not recommended for single-page sites. To enable write `enable_search: true` in in tech-docs.yml.
|
8
|
+
|
9
|
+
More info:
|
10
|
+
- https://github.com/alphagov/tech-docs-gem/pull/28
|
11
|
+
|
12
|
+
### Google Analytics tracking for old headings
|
13
|
+
|
14
|
+
An event category 'Broken fragment ID' will be pushed to Google Analytics when a user lands on a page with a URL that points to a fragment ID that does not exist on the page.
|
15
|
+
|
16
|
+
More info:
|
17
|
+
- https://github.com/alphagov/tech-docs-gem/pull/30
|
18
|
+
|
3
19
|
## 1.4.0
|
4
20
|
|
5
21
|
Adds multiple page navigation support and collapsible top level navigation
|
data/Gemfile
CHANGED
data/docs/configuration.md
CHANGED
@@ -28,6 +28,14 @@ Adds a [Google Site Verification code](https://support.google.com/webmasters/ans
|
|
28
28
|
google_site_verification: TvDTuyvdstyusadrCSDrctyd
|
29
29
|
```
|
30
30
|
|
31
|
+
## `enable_search`
|
32
|
+
|
33
|
+
Enables search functionality. This indexes pages only and is not recommended for single-page sites.
|
34
|
+
|
35
|
+
```yaml
|
36
|
+
enable_search: true
|
37
|
+
```
|
38
|
+
|
31
39
|
## `header_links`
|
32
40
|
|
33
41
|
Right hand side navigation.
|
data/govuk_tech_docs.gemspec
CHANGED
@@ -29,9 +29,11 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.add_dependency "middleman-livereload"
|
30
30
|
spec.add_dependency "middleman-sprockets", "~> 4.0.0"
|
31
31
|
spec.add_dependency "middleman-syntax", "~> 3.0.0"
|
32
|
+
spec.add_dependency "middleman-search"
|
32
33
|
spec.add_dependency "nokogiri"
|
33
34
|
spec.add_dependency "redcarpet", "~> 3.3.2"
|
34
35
|
|
36
|
+
|
35
37
|
spec.add_development_dependency "bundler", "~> 1.15"
|
36
38
|
spec.add_development_dependency "rake", "~> 10.0"
|
37
39
|
spec.add_development_dependency "capybara", "~> 2.18.0"
|
@@ -19,6 +19,20 @@
|
|
19
19
|
};
|
20
20
|
};
|
21
21
|
|
22
|
+
function catchBrokenFragmentLinks() {
|
23
|
+
var fragment = window.location.hash;
|
24
|
+
var $target = $(fragment);
|
25
|
+
if(!$target.get(0)) {
|
26
|
+
ga(
|
27
|
+
'send',
|
28
|
+
'event',
|
29
|
+
'Broken fragment ID', // Event Category
|
30
|
+
'pageview', // Event Action
|
31
|
+
window.location.pathname + fragment // Event Label
|
32
|
+
);
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
22
36
|
$(document).on('ready', function() {
|
23
37
|
if (typeof ga === 'undefined') {
|
24
38
|
return;
|
@@ -27,5 +41,6 @@
|
|
27
41
|
$('.technical-documentation a').on('click', linkTrackingEventHandler('inTextClick'));
|
28
42
|
$('.header a').on('click', linkTrackingEventHandler('topNavigationClick'));
|
29
43
|
$('.toc a').on('click', linkTrackingEventHandler('tableOfContentsNavigationClick'));
|
44
|
+
catchBrokenFragmentLinks();
|
30
45
|
});
|
31
46
|
})(jQuery);
|
@@ -0,0 +1,198 @@
|
|
1
|
+
//= require lunr.min
|
2
|
+
//= require _vendor/jquery.mark.js
|
3
|
+
(function($, Modules) {
|
4
|
+
'use strict';
|
5
|
+
|
6
|
+
Modules.Search = function Search() {
|
7
|
+
var s = this;
|
8
|
+
var $html = $('html');
|
9
|
+
s.lunrIndex;
|
10
|
+
s.lunrData;
|
11
|
+
var $searchForm;
|
12
|
+
var $searchLabel;
|
13
|
+
var $searchInput;
|
14
|
+
var $searchResults;
|
15
|
+
var $searchResultsTitle;
|
16
|
+
var $searchResultsWrapper;
|
17
|
+
var $searchResultsClose;
|
18
|
+
var results;
|
19
|
+
var maxSearchEntries = 10;
|
20
|
+
|
21
|
+
this.start = function start($element) {
|
22
|
+
$searchForm = $element.find('form');
|
23
|
+
$searchInput = $element.find('#search');
|
24
|
+
$searchLabel = $element.find('.search__label');
|
25
|
+
$searchResultsWrapper = $element.find('.search-results')
|
26
|
+
$searchResults = $searchResultsWrapper.find('.search-results__content');
|
27
|
+
$searchResultsTitle = $searchResultsWrapper.find('.search-results__title');
|
28
|
+
$searchResultsClose = $searchResultsWrapper.find('.search-results__close');
|
29
|
+
s.downloadSearchIndex();
|
30
|
+
attach();
|
31
|
+
changeSearchLabel();
|
32
|
+
};
|
33
|
+
|
34
|
+
this.downloadSearchIndex = function downloadSearchIndex() {
|
35
|
+
updateTitle('Loading search index')
|
36
|
+
$.ajax({
|
37
|
+
url: '/search.json',
|
38
|
+
cache: true,
|
39
|
+
method: 'GET',
|
40
|
+
success: function(data) {
|
41
|
+
s.lunrData = data;
|
42
|
+
s.lunrIndex = lunr.Index.load(s.lunrData.index);
|
43
|
+
$(document).trigger('lunrIndexLoaded');
|
44
|
+
}
|
45
|
+
});
|
46
|
+
}
|
47
|
+
|
48
|
+
function attach() {
|
49
|
+
// Search functionality on search text input
|
50
|
+
$searchInput.on('input', function (e) {
|
51
|
+
e.preventDefault();
|
52
|
+
var query = $(this).val();
|
53
|
+
s.search(query, function(r) {
|
54
|
+
results = r;
|
55
|
+
renderResults(query);
|
56
|
+
updateTitle();
|
57
|
+
});
|
58
|
+
});
|
59
|
+
|
60
|
+
// Set focus on the first search result instead of submiting the search
|
61
|
+
// form to Google
|
62
|
+
$searchForm.on('submit', function(e) {
|
63
|
+
e.preventDefault();
|
64
|
+
showResults();
|
65
|
+
$searchResults.find('.search-result__title a').first().focus();
|
66
|
+
});
|
67
|
+
|
68
|
+
// Closing the search results, move focus back to the search input
|
69
|
+
$searchResultsClose.on('click', function(e) {
|
70
|
+
e.preventDefault();
|
71
|
+
$searchInput.focus();
|
72
|
+
hideResults();
|
73
|
+
});
|
74
|
+
}
|
75
|
+
|
76
|
+
function changeSearchLabel() {
|
77
|
+
$searchLabel.text('Search');
|
78
|
+
}
|
79
|
+
|
80
|
+
function getResults(query) {
|
81
|
+
var results = [];
|
82
|
+
s.lunrIndex.search(query).forEach( function (item, index) {
|
83
|
+
if ( index < maxSearchEntries ) {
|
84
|
+
results.push(s.lunrData.docs[item.ref]);
|
85
|
+
}
|
86
|
+
});
|
87
|
+
|
88
|
+
return results;
|
89
|
+
}
|
90
|
+
|
91
|
+
this.search = function search(query, callback) {
|
92
|
+
if(query === '') {
|
93
|
+
hideResults();
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
showResults();
|
97
|
+
// The index has not been downloaded yet, exit early and wait.
|
98
|
+
if(!s.lunrIndex) {
|
99
|
+
$(document).on('lunrIndexLoaded', function() {
|
100
|
+
s.search(query, callback);
|
101
|
+
});
|
102
|
+
return;
|
103
|
+
}
|
104
|
+
callback(getResults(query));
|
105
|
+
}
|
106
|
+
|
107
|
+
function renderResults(query) {
|
108
|
+
var output = '';
|
109
|
+
if (results.length == 0) {
|
110
|
+
output += '<p>Nothing found</p>';
|
111
|
+
}
|
112
|
+
output += '<ul>';
|
113
|
+
for(var index in results) {
|
114
|
+
var result = results[index];
|
115
|
+
var content = s.processContent(result.content, query);
|
116
|
+
output += '<li class="search-result">';
|
117
|
+
output += '<h3 class="search-result__title">';
|
118
|
+
output += '<a href="' + result.url + '">';
|
119
|
+
output += result.title;
|
120
|
+
output += '</a>';
|
121
|
+
output += '</h3>';
|
122
|
+
if(typeof content !== 'undefined') {
|
123
|
+
output += '<p>' + content + '</p>';
|
124
|
+
}
|
125
|
+
output += '</li>';
|
126
|
+
}
|
127
|
+
output += '</ul>';
|
128
|
+
|
129
|
+
$searchResults.html( output );
|
130
|
+
}
|
131
|
+
|
132
|
+
this.processContent = function processContent(content, query) {
|
133
|
+
var output;
|
134
|
+
content = '<div>'+ content + '</div>';
|
135
|
+
content = $(content).mark(query);
|
136
|
+
|
137
|
+
// Split content by sentence.
|
138
|
+
var sentences = content.html().replace(/(\.+|\:|\!|\?|\r|\n)(\"*|\'*|\)*|}*|]*)/gm, "|").split("|");
|
139
|
+
|
140
|
+
// Select the first five sentences that contain a <mark>
|
141
|
+
var selectedSentences = [];
|
142
|
+
for (var i = 0; i < sentences.length; i++) {
|
143
|
+
if(selectedSentences.length === 5) {
|
144
|
+
break;
|
145
|
+
}
|
146
|
+
|
147
|
+
var containsMark = sentences[i].includes('mark>');
|
148
|
+
if (containsMark) {
|
149
|
+
selectedSentences.push(sentences[i].trim());
|
150
|
+
}
|
151
|
+
}
|
152
|
+
if(selectedSentences.length > 0) {
|
153
|
+
output = ' … ' + selectedSentences.join(' … ') + ' … ';
|
154
|
+
}
|
155
|
+
return output;
|
156
|
+
}
|
157
|
+
|
158
|
+
// Default text is to display the number of search results
|
159
|
+
function updateTitle(text) {
|
160
|
+
if(typeof text == "undefined") {
|
161
|
+
var count = results.length;
|
162
|
+
var text = count + ' results';
|
163
|
+
}
|
164
|
+
$searchResultsTitle.text(text);
|
165
|
+
}
|
166
|
+
|
167
|
+
function showResults() {
|
168
|
+
$searchResultsWrapper.addClass('is-open')
|
169
|
+
.attr('aria-hidden', 'false');
|
170
|
+
$html.addClass('has-search-results-open');
|
171
|
+
}
|
172
|
+
|
173
|
+
function hideResults() {
|
174
|
+
$searchResultsWrapper.removeClass('is-open')
|
175
|
+
.attr('aria-hidden', 'true');
|
176
|
+
$html.removeClass('has-search-results-open');
|
177
|
+
}
|
178
|
+
};
|
179
|
+
|
180
|
+
// Polyfill includes
|
181
|
+
if (!String.prototype.includes) {
|
182
|
+
String.prototype.includes = function(search, start) {
|
183
|
+
'use strict';
|
184
|
+
if (typeof start !== 'number') {
|
185
|
+
start = 0;
|
186
|
+
}
|
187
|
+
|
188
|
+
if (start + search.length > this.length) {
|
189
|
+
return false;
|
190
|
+
} else {
|
191
|
+
return this.indexOf(search, start) !== -1;
|
192
|
+
}
|
193
|
+
};
|
194
|
+
}
|
195
|
+
})(jQuery, window.GOVUK.Modules);
|
196
|
+
|
197
|
+
|
198
|
+
|
@@ -0,0 +1,1081 @@
|
|
1
|
+
/*!***************************************************
|
2
|
+
* mark.js v8.11.1
|
3
|
+
* https://markjs.io/
|
4
|
+
* Copyright (c) 2014–2018, Julian Kühnel
|
5
|
+
* Released under the MIT license https://git.io/vwTVl
|
6
|
+
*****************************************************/
|
7
|
+
|
8
|
+
(function (global, factory) {
|
9
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) :
|
10
|
+
typeof define === 'function' && define.amd ? define(['jquery'], factory) :
|
11
|
+
(global.Mark = factory(global.jQuery));
|
12
|
+
}(this, (function ($) { 'use strict';
|
13
|
+
|
14
|
+
$ = $ && $.hasOwnProperty('default') ? $['default'] : $;
|
15
|
+
|
16
|
+
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
17
|
+
return typeof obj;
|
18
|
+
} : function (obj) {
|
19
|
+
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
20
|
+
};
|
21
|
+
|
22
|
+
var classCallCheck = function (instance, Constructor) {
|
23
|
+
if (!(instance instanceof Constructor)) {
|
24
|
+
throw new TypeError("Cannot call a class as a function");
|
25
|
+
}
|
26
|
+
};
|
27
|
+
|
28
|
+
var createClass = function () {
|
29
|
+
function defineProperties(target, props) {
|
30
|
+
for (var i = 0; i < props.length; i++) {
|
31
|
+
var descriptor = props[i];
|
32
|
+
descriptor.enumerable = descriptor.enumerable || false;
|
33
|
+
descriptor.configurable = true;
|
34
|
+
if ("value" in descriptor) descriptor.writable = true;
|
35
|
+
Object.defineProperty(target, descriptor.key, descriptor);
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
return function (Constructor, protoProps, staticProps) {
|
40
|
+
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
41
|
+
if (staticProps) defineProperties(Constructor, staticProps);
|
42
|
+
return Constructor;
|
43
|
+
};
|
44
|
+
}();
|
45
|
+
|
46
|
+
var _extends = Object.assign || function (target) {
|
47
|
+
for (var i = 1; i < arguments.length; i++) {
|
48
|
+
var source = arguments[i];
|
49
|
+
|
50
|
+
for (var key in source) {
|
51
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
52
|
+
target[key] = source[key];
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
return target;
|
58
|
+
};
|
59
|
+
|
60
|
+
var DOMIterator = function () {
|
61
|
+
function DOMIterator(ctx) {
|
62
|
+
var iframes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
63
|
+
var exclude = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
|
64
|
+
var iframesTimeout = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 5000;
|
65
|
+
classCallCheck(this, DOMIterator);
|
66
|
+
|
67
|
+
this.ctx = ctx;
|
68
|
+
this.iframes = iframes;
|
69
|
+
this.exclude = exclude;
|
70
|
+
this.iframesTimeout = iframesTimeout;
|
71
|
+
}
|
72
|
+
|
73
|
+
createClass(DOMIterator, [{
|
74
|
+
key: 'getContexts',
|
75
|
+
value: function getContexts() {
|
76
|
+
var ctx = void 0,
|
77
|
+
filteredCtx = [];
|
78
|
+
if (typeof this.ctx === 'undefined' || !this.ctx) {
|
79
|
+
ctx = [];
|
80
|
+
} else if (NodeList.prototype.isPrototypeOf(this.ctx)) {
|
81
|
+
ctx = Array.prototype.slice.call(this.ctx);
|
82
|
+
} else if (Array.isArray(this.ctx)) {
|
83
|
+
ctx = this.ctx;
|
84
|
+
} else if (typeof this.ctx === 'string') {
|
85
|
+
ctx = Array.prototype.slice.call(document.querySelectorAll(this.ctx));
|
86
|
+
} else {
|
87
|
+
ctx = [this.ctx];
|
88
|
+
}
|
89
|
+
ctx.forEach(function (ctx) {
|
90
|
+
var isDescendant = filteredCtx.filter(function (contexts) {
|
91
|
+
return contexts.contains(ctx);
|
92
|
+
}).length > 0;
|
93
|
+
if (filteredCtx.indexOf(ctx) === -1 && !isDescendant) {
|
94
|
+
filteredCtx.push(ctx);
|
95
|
+
}
|
96
|
+
});
|
97
|
+
return filteredCtx;
|
98
|
+
}
|
99
|
+
}, {
|
100
|
+
key: 'getIframeContents',
|
101
|
+
value: function getIframeContents(ifr, successFn) {
|
102
|
+
var errorFn = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function () {};
|
103
|
+
|
104
|
+
var doc = void 0;
|
105
|
+
try {
|
106
|
+
var ifrWin = ifr.contentWindow;
|
107
|
+
doc = ifrWin.document;
|
108
|
+
if (!ifrWin || !doc) {
|
109
|
+
throw new Error('iframe inaccessible');
|
110
|
+
}
|
111
|
+
} catch (e) {
|
112
|
+
errorFn();
|
113
|
+
}
|
114
|
+
if (doc) {
|
115
|
+
successFn(doc);
|
116
|
+
}
|
117
|
+
}
|
118
|
+
}, {
|
119
|
+
key: 'isIframeBlank',
|
120
|
+
value: function isIframeBlank(ifr) {
|
121
|
+
var bl = 'about:blank',
|
122
|
+
src = ifr.getAttribute('src').trim(),
|
123
|
+
href = ifr.contentWindow.location.href;
|
124
|
+
return href === bl && src !== bl && src;
|
125
|
+
}
|
126
|
+
}, {
|
127
|
+
key: 'observeIframeLoad',
|
128
|
+
value: function observeIframeLoad(ifr, successFn, errorFn) {
|
129
|
+
var _this = this;
|
130
|
+
|
131
|
+
var called = false,
|
132
|
+
tout = null;
|
133
|
+
var listener = function listener() {
|
134
|
+
if (called) {
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
called = true;
|
138
|
+
clearTimeout(tout);
|
139
|
+
try {
|
140
|
+
if (!_this.isIframeBlank(ifr)) {
|
141
|
+
ifr.removeEventListener('load', listener);
|
142
|
+
_this.getIframeContents(ifr, successFn, errorFn);
|
143
|
+
}
|
144
|
+
} catch (e) {
|
145
|
+
errorFn();
|
146
|
+
}
|
147
|
+
};
|
148
|
+
ifr.addEventListener('load', listener);
|
149
|
+
tout = setTimeout(listener, this.iframesTimeout);
|
150
|
+
}
|
151
|
+
}, {
|
152
|
+
key: 'onIframeReady',
|
153
|
+
value: function onIframeReady(ifr, successFn, errorFn) {
|
154
|
+
try {
|
155
|
+
if (ifr.contentWindow.document.readyState === 'complete') {
|
156
|
+
if (this.isIframeBlank(ifr)) {
|
157
|
+
this.observeIframeLoad(ifr, successFn, errorFn);
|
158
|
+
} else {
|
159
|
+
this.getIframeContents(ifr, successFn, errorFn);
|
160
|
+
}
|
161
|
+
} else {
|
162
|
+
this.observeIframeLoad(ifr, successFn, errorFn);
|
163
|
+
}
|
164
|
+
} catch (e) {
|
165
|
+
errorFn();
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}, {
|
169
|
+
key: 'waitForIframes',
|
170
|
+
value: function waitForIframes(ctx, done) {
|
171
|
+
var _this2 = this;
|
172
|
+
|
173
|
+
var eachCalled = 0;
|
174
|
+
this.forEachIframe(ctx, function () {
|
175
|
+
return true;
|
176
|
+
}, function (ifr) {
|
177
|
+
eachCalled++;
|
178
|
+
_this2.waitForIframes(ifr.querySelector('html'), function () {
|
179
|
+
if (! --eachCalled) {
|
180
|
+
done();
|
181
|
+
}
|
182
|
+
});
|
183
|
+
}, function (handled) {
|
184
|
+
if (!handled) {
|
185
|
+
done();
|
186
|
+
}
|
187
|
+
});
|
188
|
+
}
|
189
|
+
}, {
|
190
|
+
key: 'forEachIframe',
|
191
|
+
value: function forEachIframe(ctx, filter, each) {
|
192
|
+
var _this3 = this;
|
193
|
+
|
194
|
+
var end = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};
|
195
|
+
|
196
|
+
var ifr = ctx.querySelectorAll('iframe'),
|
197
|
+
open = ifr.length,
|
198
|
+
handled = 0;
|
199
|
+
ifr = Array.prototype.slice.call(ifr);
|
200
|
+
var checkEnd = function checkEnd() {
|
201
|
+
if (--open <= 0) {
|
202
|
+
end(handled);
|
203
|
+
}
|
204
|
+
};
|
205
|
+
if (!open) {
|
206
|
+
checkEnd();
|
207
|
+
}
|
208
|
+
ifr.forEach(function (ifr) {
|
209
|
+
if (DOMIterator.matches(ifr, _this3.exclude)) {
|
210
|
+
checkEnd();
|
211
|
+
} else {
|
212
|
+
_this3.onIframeReady(ifr, function (con) {
|
213
|
+
if (filter(ifr)) {
|
214
|
+
handled++;
|
215
|
+
each(con);
|
216
|
+
}
|
217
|
+
checkEnd();
|
218
|
+
}, checkEnd);
|
219
|
+
}
|
220
|
+
});
|
221
|
+
}
|
222
|
+
}, {
|
223
|
+
key: 'createIterator',
|
224
|
+
value: function createIterator(ctx, whatToShow, filter) {
|
225
|
+
return document.createNodeIterator(ctx, whatToShow, filter, false);
|
226
|
+
}
|
227
|
+
}, {
|
228
|
+
key: 'createInstanceOnIframe',
|
229
|
+
value: function createInstanceOnIframe(contents) {
|
230
|
+
return new DOMIterator(contents.querySelector('html'), this.iframes);
|
231
|
+
}
|
232
|
+
}, {
|
233
|
+
key: 'compareNodeIframe',
|
234
|
+
value: function compareNodeIframe(node, prevNode, ifr) {
|
235
|
+
var compCurr = node.compareDocumentPosition(ifr),
|
236
|
+
prev = Node.DOCUMENT_POSITION_PRECEDING;
|
237
|
+
if (compCurr & prev) {
|
238
|
+
if (prevNode !== null) {
|
239
|
+
var compPrev = prevNode.compareDocumentPosition(ifr),
|
240
|
+
after = Node.DOCUMENT_POSITION_FOLLOWING;
|
241
|
+
if (compPrev & after) {
|
242
|
+
return true;
|
243
|
+
}
|
244
|
+
} else {
|
245
|
+
return true;
|
246
|
+
}
|
247
|
+
}
|
248
|
+
return false;
|
249
|
+
}
|
250
|
+
}, {
|
251
|
+
key: 'getIteratorNode',
|
252
|
+
value: function getIteratorNode(itr) {
|
253
|
+
var prevNode = itr.previousNode();
|
254
|
+
var node = void 0;
|
255
|
+
if (prevNode === null) {
|
256
|
+
node = itr.nextNode();
|
257
|
+
} else {
|
258
|
+
node = itr.nextNode() && itr.nextNode();
|
259
|
+
}
|
260
|
+
return {
|
261
|
+
prevNode: prevNode,
|
262
|
+
node: node
|
263
|
+
};
|
264
|
+
}
|
265
|
+
}, {
|
266
|
+
key: 'checkIframeFilter',
|
267
|
+
value: function checkIframeFilter(node, prevNode, currIfr, ifr) {
|
268
|
+
var key = false,
|
269
|
+
handled = false;
|
270
|
+
ifr.forEach(function (ifrDict, i) {
|
271
|
+
if (ifrDict.val === currIfr) {
|
272
|
+
key = i;
|
273
|
+
handled = ifrDict.handled;
|
274
|
+
}
|
275
|
+
});
|
276
|
+
if (this.compareNodeIframe(node, prevNode, currIfr)) {
|
277
|
+
if (key === false && !handled) {
|
278
|
+
ifr.push({
|
279
|
+
val: currIfr,
|
280
|
+
handled: true
|
281
|
+
});
|
282
|
+
} else if (key !== false && !handled) {
|
283
|
+
ifr[key].handled = true;
|
284
|
+
}
|
285
|
+
return true;
|
286
|
+
}
|
287
|
+
if (key === false) {
|
288
|
+
ifr.push({
|
289
|
+
val: currIfr,
|
290
|
+
handled: false
|
291
|
+
});
|
292
|
+
}
|
293
|
+
return false;
|
294
|
+
}
|
295
|
+
}, {
|
296
|
+
key: 'handleOpenIframes',
|
297
|
+
value: function handleOpenIframes(ifr, whatToShow, eCb, fCb) {
|
298
|
+
var _this4 = this;
|
299
|
+
|
300
|
+
ifr.forEach(function (ifrDict) {
|
301
|
+
if (!ifrDict.handled) {
|
302
|
+
_this4.getIframeContents(ifrDict.val, function (con) {
|
303
|
+
_this4.createInstanceOnIframe(con).forEachNode(whatToShow, eCb, fCb);
|
304
|
+
});
|
305
|
+
}
|
306
|
+
});
|
307
|
+
}
|
308
|
+
}, {
|
309
|
+
key: 'iterateThroughNodes',
|
310
|
+
value: function iterateThroughNodes(whatToShow, ctx, eachCb, filterCb, doneCb) {
|
311
|
+
var _this5 = this;
|
312
|
+
|
313
|
+
var itr = this.createIterator(ctx, whatToShow, filterCb);
|
314
|
+
var ifr = [],
|
315
|
+
elements = [],
|
316
|
+
node = void 0,
|
317
|
+
prevNode = void 0,
|
318
|
+
retrieveNodes = function retrieveNodes() {
|
319
|
+
var _getIteratorNode = _this5.getIteratorNode(itr);
|
320
|
+
|
321
|
+
prevNode = _getIteratorNode.prevNode;
|
322
|
+
node = _getIteratorNode.node;
|
323
|
+
|
324
|
+
return node;
|
325
|
+
};
|
326
|
+
while (retrieveNodes()) {
|
327
|
+
if (this.iframes) {
|
328
|
+
this.forEachIframe(ctx, function (currIfr) {
|
329
|
+
return _this5.checkIframeFilter(node, prevNode, currIfr, ifr);
|
330
|
+
}, function (con) {
|
331
|
+
_this5.createInstanceOnIframe(con).forEachNode(whatToShow, function (ifrNode) {
|
332
|
+
return elements.push(ifrNode);
|
333
|
+
}, filterCb);
|
334
|
+
});
|
335
|
+
}
|
336
|
+
elements.push(node);
|
337
|
+
}
|
338
|
+
elements.forEach(function (node) {
|
339
|
+
eachCb(node);
|
340
|
+
});
|
341
|
+
if (this.iframes) {
|
342
|
+
this.handleOpenIframes(ifr, whatToShow, eachCb, filterCb);
|
343
|
+
}
|
344
|
+
doneCb();
|
345
|
+
}
|
346
|
+
}, {
|
347
|
+
key: 'forEachNode',
|
348
|
+
value: function forEachNode(whatToShow, each, filter) {
|
349
|
+
var _this6 = this;
|
350
|
+
|
351
|
+
var done = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : function () {};
|
352
|
+
|
353
|
+
var contexts = this.getContexts();
|
354
|
+
var open = contexts.length;
|
355
|
+
if (!open) {
|
356
|
+
done();
|
357
|
+
}
|
358
|
+
contexts.forEach(function (ctx) {
|
359
|
+
var ready = function ready() {
|
360
|
+
_this6.iterateThroughNodes(whatToShow, ctx, each, filter, function () {
|
361
|
+
if (--open <= 0) {
|
362
|
+
done();
|
363
|
+
}
|
364
|
+
});
|
365
|
+
};
|
366
|
+
if (_this6.iframes) {
|
367
|
+
_this6.waitForIframes(ctx, ready);
|
368
|
+
} else {
|
369
|
+
ready();
|
370
|
+
}
|
371
|
+
});
|
372
|
+
}
|
373
|
+
}], [{
|
374
|
+
key: 'matches',
|
375
|
+
value: function matches(element, selector) {
|
376
|
+
var selectors = typeof selector === 'string' ? [selector] : selector,
|
377
|
+
fn = element.matches || element.matchesSelector || element.msMatchesSelector || element.mozMatchesSelector || element.oMatchesSelector || element.webkitMatchesSelector;
|
378
|
+
if (fn) {
|
379
|
+
var match = false;
|
380
|
+
selectors.every(function (sel) {
|
381
|
+
if (fn.call(element, sel)) {
|
382
|
+
match = true;
|
383
|
+
return false;
|
384
|
+
}
|
385
|
+
return true;
|
386
|
+
});
|
387
|
+
return match;
|
388
|
+
} else {
|
389
|
+
return false;
|
390
|
+
}
|
391
|
+
}
|
392
|
+
}]);
|
393
|
+
return DOMIterator;
|
394
|
+
}();
|
395
|
+
|
396
|
+
var RegExpCreator = function () {
|
397
|
+
function RegExpCreator(options) {
|
398
|
+
classCallCheck(this, RegExpCreator);
|
399
|
+
|
400
|
+
this.opt = _extends({}, {
|
401
|
+
'diacritics': true,
|
402
|
+
'synonyms': {},
|
403
|
+
'accuracy': 'partially',
|
404
|
+
'caseSensitive': false,
|
405
|
+
'ignoreJoiners': false,
|
406
|
+
'ignorePunctuation': [],
|
407
|
+
'wildcards': 'disabled'
|
408
|
+
}, options);
|
409
|
+
}
|
410
|
+
|
411
|
+
createClass(RegExpCreator, [{
|
412
|
+
key: 'create',
|
413
|
+
value: function create(str) {
|
414
|
+
if (this.opt.wildcards !== 'disabled') {
|
415
|
+
str = this.setupWildcardsRegExp(str);
|
416
|
+
}
|
417
|
+
str = this.escapeStr(str);
|
418
|
+
if (Object.keys(this.opt.synonyms).length) {
|
419
|
+
str = this.createSynonymsRegExp(str);
|
420
|
+
}
|
421
|
+
if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
|
422
|
+
str = this.setupIgnoreJoinersRegExp(str);
|
423
|
+
}
|
424
|
+
if (this.opt.diacritics) {
|
425
|
+
str = this.createDiacriticsRegExp(str);
|
426
|
+
}
|
427
|
+
str = this.createMergedBlanksRegExp(str);
|
428
|
+
if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
|
429
|
+
str = this.createJoinersRegExp(str);
|
430
|
+
}
|
431
|
+
if (this.opt.wildcards !== 'disabled') {
|
432
|
+
str = this.createWildcardsRegExp(str);
|
433
|
+
}
|
434
|
+
str = this.createAccuracyRegExp(str);
|
435
|
+
return new RegExp(str, 'gm' + (this.opt.caseSensitive ? '' : 'i'));
|
436
|
+
}
|
437
|
+
}, {
|
438
|
+
key: 'escapeStr',
|
439
|
+
value: function escapeStr(str) {
|
440
|
+
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
441
|
+
}
|
442
|
+
}, {
|
443
|
+
key: 'createSynonymsRegExp',
|
444
|
+
value: function createSynonymsRegExp(str) {
|
445
|
+
var syn = this.opt.synonyms,
|
446
|
+
sens = this.opt.caseSensitive ? '' : 'i',
|
447
|
+
joinerPlaceholder = this.opt.ignoreJoiners || this.opt.ignorePunctuation.length ? '\0' : '';
|
448
|
+
for (var index in syn) {
|
449
|
+
if (syn.hasOwnProperty(index)) {
|
450
|
+
var value = syn[index],
|
451
|
+
k1 = this.opt.wildcards !== 'disabled' ? this.setupWildcardsRegExp(index) : this.escapeStr(index),
|
452
|
+
k2 = this.opt.wildcards !== 'disabled' ? this.setupWildcardsRegExp(value) : this.escapeStr(value);
|
453
|
+
if (k1 !== '' && k2 !== '') {
|
454
|
+
str = str.replace(new RegExp('(' + this.escapeStr(k1) + '|' + this.escapeStr(k2) + ')', 'gm' + sens), joinerPlaceholder + ('(' + this.processSynonyms(k1) + '|') + (this.processSynonyms(k2) + ')') + joinerPlaceholder);
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
return str;
|
459
|
+
}
|
460
|
+
}, {
|
461
|
+
key: 'processSynonyms',
|
462
|
+
value: function processSynonyms(str) {
|
463
|
+
if (this.opt.ignoreJoiners || this.opt.ignorePunctuation.length) {
|
464
|
+
str = this.setupIgnoreJoinersRegExp(str);
|
465
|
+
}
|
466
|
+
return str;
|
467
|
+
}
|
468
|
+
}, {
|
469
|
+
key: 'setupWildcardsRegExp',
|
470
|
+
value: function setupWildcardsRegExp(str) {
|
471
|
+
str = str.replace(/(?:\\)*\?/g, function (val) {
|
472
|
+
return val.charAt(0) === '\\' ? '?' : '\x01';
|
473
|
+
});
|
474
|
+
return str.replace(/(?:\\)*\*/g, function (val) {
|
475
|
+
return val.charAt(0) === '\\' ? '*' : '\x02';
|
476
|
+
});
|
477
|
+
}
|
478
|
+
}, {
|
479
|
+
key: 'createWildcardsRegExp',
|
480
|
+
value: function createWildcardsRegExp(str) {
|
481
|
+
var spaces = this.opt.wildcards === 'withSpaces';
|
482
|
+
return str.replace(/\u0001/g, spaces ? '[\\S\\s]?' : '\\S?').replace(/\u0002/g, spaces ? '[\\S\\s]*?' : '\\S*');
|
483
|
+
}
|
484
|
+
}, {
|
485
|
+
key: 'setupIgnoreJoinersRegExp',
|
486
|
+
value: function setupIgnoreJoinersRegExp(str) {
|
487
|
+
return str.replace(/[^(|)\\]/g, function (val, indx, original) {
|
488
|
+
var nextChar = original.charAt(indx + 1);
|
489
|
+
if (/[(|)\\]/.test(nextChar) || nextChar === '') {
|
490
|
+
return val;
|
491
|
+
} else {
|
492
|
+
return val + '\0';
|
493
|
+
}
|
494
|
+
});
|
495
|
+
}
|
496
|
+
}, {
|
497
|
+
key: 'createJoinersRegExp',
|
498
|
+
value: function createJoinersRegExp(str) {
|
499
|
+
var joiner = [];
|
500
|
+
var ignorePunctuation = this.opt.ignorePunctuation;
|
501
|
+
if (Array.isArray(ignorePunctuation) && ignorePunctuation.length) {
|
502
|
+
joiner.push(this.escapeStr(ignorePunctuation.join('')));
|
503
|
+
}
|
504
|
+
if (this.opt.ignoreJoiners) {
|
505
|
+
joiner.push('\\u00ad\\u200b\\u200c\\u200d');
|
506
|
+
}
|
507
|
+
return joiner.length ? str.split(/\u0000+/).join('[' + joiner.join('') + ']*') : str;
|
508
|
+
}
|
509
|
+
}, {
|
510
|
+
key: 'createDiacriticsRegExp',
|
511
|
+
value: function createDiacriticsRegExp(str) {
|
512
|
+
var sens = this.opt.caseSensitive ? '' : 'i',
|
513
|
+
dct = this.opt.caseSensitive ? ['aàáảãạăằắẳẵặâầấẩẫậäåāą', 'AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 'cçćč', 'CÇĆČ', 'dđď', 'DĐĎ', 'eèéẻẽẹêềếểễệëěēę', 'EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ', 'iìíỉĩịîïī', 'IÌÍỈĨỊÎÏĪ', 'lł', 'LŁ', 'nñňń', 'NÑŇŃ', 'oòóỏõọôồốổỗộơởỡớờợöøō', 'OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 'rř', 'RŘ', 'sšśșş', 'SŠŚȘŞ', 'tťțţ', 'TŤȚŢ', 'uùúủũụưừứửữựûüůū', 'UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 'yýỳỷỹỵÿ', 'YÝỲỶỸỴŸ', 'zžżź', 'ZŽŻŹ'] : ['aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ', 'cçćčCÇĆČ', 'dđďDĐĎ', 'eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ', 'iìíỉĩịîïīIÌÍỈĨỊÎÏĪ', 'lłLŁ', 'nñňńNÑŇŃ', 'oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ', 'rřRŘ', 'sšśșşSŠŚȘŞ', 'tťțţTŤȚŢ', 'uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ', 'yýỳỷỹỵÿYÝỲỶỸỴŸ', 'zžżźZŽŻŹ'];
|
514
|
+
var handled = [];
|
515
|
+
str.split('').forEach(function (ch) {
|
516
|
+
dct.every(function (dct) {
|
517
|
+
if (dct.indexOf(ch) !== -1) {
|
518
|
+
if (handled.indexOf(dct) > -1) {
|
519
|
+
return false;
|
520
|
+
}
|
521
|
+
str = str.replace(new RegExp('[' + dct + ']', 'gm' + sens), '[' + dct + ']');
|
522
|
+
handled.push(dct);
|
523
|
+
}
|
524
|
+
return true;
|
525
|
+
});
|
526
|
+
});
|
527
|
+
return str;
|
528
|
+
}
|
529
|
+
}, {
|
530
|
+
key: 'createMergedBlanksRegExp',
|
531
|
+
value: function createMergedBlanksRegExp(str) {
|
532
|
+
return str.replace(/[\s]+/gmi, '[\\s]+');
|
533
|
+
}
|
534
|
+
}, {
|
535
|
+
key: 'createAccuracyRegExp',
|
536
|
+
value: function createAccuracyRegExp(str) {
|
537
|
+
var _this = this;
|
538
|
+
|
539
|
+
var chars = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~¡¿';
|
540
|
+
var acc = this.opt.accuracy,
|
541
|
+
val = typeof acc === 'string' ? acc : acc.value,
|
542
|
+
ls = typeof acc === 'string' ? [] : acc.limiters,
|
543
|
+
lsJoin = '';
|
544
|
+
ls.forEach(function (limiter) {
|
545
|
+
lsJoin += '|' + _this.escapeStr(limiter);
|
546
|
+
});
|
547
|
+
switch (val) {
|
548
|
+
case 'partially':
|
549
|
+
default:
|
550
|
+
return '()(' + str + ')';
|
551
|
+
case 'complementary':
|
552
|
+
lsJoin = '\\s' + (lsJoin ? lsJoin : this.escapeStr(chars));
|
553
|
+
return '()([^' + lsJoin + ']*' + str + '[^' + lsJoin + ']*)';
|
554
|
+
case 'exactly':
|
555
|
+
return '(^|\\s' + lsJoin + ')(' + str + ')(?=$|\\s' + lsJoin + ')';
|
556
|
+
}
|
557
|
+
}
|
558
|
+
}]);
|
559
|
+
return RegExpCreator;
|
560
|
+
}();
|
561
|
+
|
562
|
+
var Mark = function () {
|
563
|
+
function Mark(ctx) {
|
564
|
+
classCallCheck(this, Mark);
|
565
|
+
|
566
|
+
this.ctx = ctx;
|
567
|
+
this.ie = false;
|
568
|
+
var ua = window.navigator.userAgent;
|
569
|
+
if (ua.indexOf('MSIE') > -1 || ua.indexOf('Trident') > -1) {
|
570
|
+
this.ie = true;
|
571
|
+
}
|
572
|
+
}
|
573
|
+
|
574
|
+
createClass(Mark, [{
|
575
|
+
key: 'log',
|
576
|
+
value: function log(msg) {
|
577
|
+
var level = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'debug';
|
578
|
+
|
579
|
+
var log = this.opt.log;
|
580
|
+
if (!this.opt.debug) {
|
581
|
+
return;
|
582
|
+
}
|
583
|
+
if ((typeof log === 'undefined' ? 'undefined' : _typeof(log)) === 'object' && typeof log[level] === 'function') {
|
584
|
+
log[level]('mark.js: ' + msg);
|
585
|
+
}
|
586
|
+
}
|
587
|
+
}, {
|
588
|
+
key: 'getSeparatedKeywords',
|
589
|
+
value: function getSeparatedKeywords(sv) {
|
590
|
+
var _this = this;
|
591
|
+
|
592
|
+
var stack = [];
|
593
|
+
sv.forEach(function (kw) {
|
594
|
+
if (!_this.opt.separateWordSearch) {
|
595
|
+
if (kw.trim() && stack.indexOf(kw) === -1) {
|
596
|
+
stack.push(kw);
|
597
|
+
}
|
598
|
+
} else {
|
599
|
+
kw.split(' ').forEach(function (kwSplitted) {
|
600
|
+
if (kwSplitted.trim() && stack.indexOf(kwSplitted) === -1) {
|
601
|
+
stack.push(kwSplitted);
|
602
|
+
}
|
603
|
+
});
|
604
|
+
}
|
605
|
+
});
|
606
|
+
return {
|
607
|
+
'keywords': stack.sort(function (a, b) {
|
608
|
+
return b.length - a.length;
|
609
|
+
}),
|
610
|
+
'length': stack.length
|
611
|
+
};
|
612
|
+
}
|
613
|
+
}, {
|
614
|
+
key: 'isNumeric',
|
615
|
+
value: function isNumeric(value) {
|
616
|
+
return Number(parseFloat(value)) == value;
|
617
|
+
}
|
618
|
+
}, {
|
619
|
+
key: 'checkRanges',
|
620
|
+
value: function checkRanges(array) {
|
621
|
+
var _this2 = this;
|
622
|
+
|
623
|
+
if (!Array.isArray(array) || Object.prototype.toString.call(array[0]) !== '[object Object]') {
|
624
|
+
this.log('markRanges() will only accept an array of objects');
|
625
|
+
this.opt.noMatch(array);
|
626
|
+
return [];
|
627
|
+
}
|
628
|
+
var stack = [];
|
629
|
+
var last = 0;
|
630
|
+
array.sort(function (a, b) {
|
631
|
+
return a.start - b.start;
|
632
|
+
}).forEach(function (item) {
|
633
|
+
var _callNoMatchOnInvalid = _this2.callNoMatchOnInvalidRanges(item, last),
|
634
|
+
start = _callNoMatchOnInvalid.start,
|
635
|
+
end = _callNoMatchOnInvalid.end,
|
636
|
+
valid = _callNoMatchOnInvalid.valid;
|
637
|
+
|
638
|
+
if (valid) {
|
639
|
+
item.start = start;
|
640
|
+
item.length = end - start;
|
641
|
+
stack.push(item);
|
642
|
+
last = end;
|
643
|
+
}
|
644
|
+
});
|
645
|
+
return stack;
|
646
|
+
}
|
647
|
+
}, {
|
648
|
+
key: 'callNoMatchOnInvalidRanges',
|
649
|
+
value: function callNoMatchOnInvalidRanges(range, last) {
|
650
|
+
var start = void 0,
|
651
|
+
end = void 0,
|
652
|
+
valid = false;
|
653
|
+
if (range && typeof range.start !== 'undefined') {
|
654
|
+
start = parseInt(range.start, 10);
|
655
|
+
end = start + parseInt(range.length, 10);
|
656
|
+
if (this.isNumeric(range.start) && this.isNumeric(range.length) && end - last > 0 && end - start > 0) {
|
657
|
+
valid = true;
|
658
|
+
} else {
|
659
|
+
this.log('Ignoring invalid or overlapping range: ' + ('' + JSON.stringify(range)));
|
660
|
+
this.opt.noMatch(range);
|
661
|
+
}
|
662
|
+
} else {
|
663
|
+
this.log('Ignoring invalid range: ' + JSON.stringify(range));
|
664
|
+
this.opt.noMatch(range);
|
665
|
+
}
|
666
|
+
return {
|
667
|
+
start: start,
|
668
|
+
end: end,
|
669
|
+
valid: valid
|
670
|
+
};
|
671
|
+
}
|
672
|
+
}, {
|
673
|
+
key: 'checkWhitespaceRanges',
|
674
|
+
value: function checkWhitespaceRanges(range, originalLength, string) {
|
675
|
+
var end = void 0,
|
676
|
+
valid = true,
|
677
|
+
max = string.length,
|
678
|
+
offset = originalLength - max,
|
679
|
+
start = parseInt(range.start, 10) - offset;
|
680
|
+
start = start > max ? max : start;
|
681
|
+
end = start + parseInt(range.length, 10);
|
682
|
+
if (end > max) {
|
683
|
+
end = max;
|
684
|
+
this.log('End range automatically set to the max value of ' + max);
|
685
|
+
}
|
686
|
+
if (start < 0 || end - start < 0 || start > max || end > max) {
|
687
|
+
valid = false;
|
688
|
+
this.log('Invalid range: ' + JSON.stringify(range));
|
689
|
+
this.opt.noMatch(range);
|
690
|
+
} else if (string.substring(start, end).replace(/\s+/g, '') === '') {
|
691
|
+
valid = false;
|
692
|
+
this.log('Skipping whitespace only range: ' + JSON.stringify(range));
|
693
|
+
this.opt.noMatch(range);
|
694
|
+
}
|
695
|
+
return {
|
696
|
+
start: start,
|
697
|
+
end: end,
|
698
|
+
valid: valid
|
699
|
+
};
|
700
|
+
}
|
701
|
+
}, {
|
702
|
+
key: 'getTextNodes',
|
703
|
+
value: function getTextNodes(cb) {
|
704
|
+
var _this3 = this;
|
705
|
+
|
706
|
+
var val = '',
|
707
|
+
nodes = [];
|
708
|
+
this.iterator.forEachNode(NodeFilter.SHOW_TEXT, function (node) {
|
709
|
+
nodes.push({
|
710
|
+
start: val.length,
|
711
|
+
end: (val += node.textContent).length,
|
712
|
+
node: node
|
713
|
+
});
|
714
|
+
}, function (node) {
|
715
|
+
if (_this3.matchesExclude(node.parentNode)) {
|
716
|
+
return NodeFilter.FILTER_REJECT;
|
717
|
+
} else {
|
718
|
+
return NodeFilter.FILTER_ACCEPT;
|
719
|
+
}
|
720
|
+
}, function () {
|
721
|
+
cb({
|
722
|
+
value: val,
|
723
|
+
nodes: nodes
|
724
|
+
});
|
725
|
+
});
|
726
|
+
}
|
727
|
+
}, {
|
728
|
+
key: 'matchesExclude',
|
729
|
+
value: function matchesExclude(el) {
|
730
|
+
return DOMIterator.matches(el, this.opt.exclude.concat(['script', 'style', 'title', 'head', 'html']));
|
731
|
+
}
|
732
|
+
}, {
|
733
|
+
key: 'wrapRangeInTextNode',
|
734
|
+
value: function wrapRangeInTextNode(node, start, end) {
|
735
|
+
var hEl = !this.opt.element ? 'mark' : this.opt.element,
|
736
|
+
startNode = node.splitText(start),
|
737
|
+
ret = startNode.splitText(end - start);
|
738
|
+
var repl = document.createElement(hEl);
|
739
|
+
repl.setAttribute('data-markjs', 'true');
|
740
|
+
if (this.opt.className) {
|
741
|
+
repl.setAttribute('class', this.opt.className);
|
742
|
+
}
|
743
|
+
repl.textContent = startNode.textContent;
|
744
|
+
startNode.parentNode.replaceChild(repl, startNode);
|
745
|
+
return ret;
|
746
|
+
}
|
747
|
+
}, {
|
748
|
+
key: 'wrapRangeInMappedTextNode',
|
749
|
+
value: function wrapRangeInMappedTextNode(dict, start, end, filterCb, eachCb) {
|
750
|
+
var _this4 = this;
|
751
|
+
|
752
|
+
dict.nodes.every(function (n, i) {
|
753
|
+
var sibl = dict.nodes[i + 1];
|
754
|
+
if (typeof sibl === 'undefined' || sibl.start > start) {
|
755
|
+
if (!filterCb(n.node)) {
|
756
|
+
return false;
|
757
|
+
}
|
758
|
+
var s = start - n.start,
|
759
|
+
e = (end > n.end ? n.end : end) - n.start,
|
760
|
+
startStr = dict.value.substr(0, n.start),
|
761
|
+
endStr = dict.value.substr(e + n.start);
|
762
|
+
n.node = _this4.wrapRangeInTextNode(n.node, s, e);
|
763
|
+
dict.value = startStr + endStr;
|
764
|
+
dict.nodes.forEach(function (k, j) {
|
765
|
+
if (j >= i) {
|
766
|
+
if (dict.nodes[j].start > 0 && j !== i) {
|
767
|
+
dict.nodes[j].start -= e;
|
768
|
+
}
|
769
|
+
dict.nodes[j].end -= e;
|
770
|
+
}
|
771
|
+
});
|
772
|
+
end -= e;
|
773
|
+
eachCb(n.node.previousSibling, n.start);
|
774
|
+
if (end > n.end) {
|
775
|
+
start = n.end;
|
776
|
+
} else {
|
777
|
+
return false;
|
778
|
+
}
|
779
|
+
}
|
780
|
+
return true;
|
781
|
+
});
|
782
|
+
}
|
783
|
+
}, {
|
784
|
+
key: 'wrapGroups',
|
785
|
+
value: function wrapGroups(node, pos, len, eachCb) {
|
786
|
+
node = this.wrapRangeInTextNode(node, pos, pos + len);
|
787
|
+
eachCb(node.previousSibling);
|
788
|
+
return node;
|
789
|
+
}
|
790
|
+
}, {
|
791
|
+
key: 'separateGroups',
|
792
|
+
value: function separateGroups(node, match, matchIdx, filterCb, eachCb) {
|
793
|
+
var matchLen = match.length;
|
794
|
+
for (var i = 1; i < matchLen; i++) {
|
795
|
+
var pos = node.textContent.indexOf(match[i]);
|
796
|
+
if (match[i] && pos > -1 && filterCb(match[i], node)) {
|
797
|
+
node = this.wrapGroups(node, pos, match[i].length, eachCb);
|
798
|
+
}
|
799
|
+
}
|
800
|
+
return node;
|
801
|
+
}
|
802
|
+
}, {
|
803
|
+
key: 'wrapMatches',
|
804
|
+
value: function wrapMatches(regex, ignoreGroups, filterCb, eachCb, endCb) {
|
805
|
+
var _this5 = this;
|
806
|
+
|
807
|
+
var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;
|
808
|
+
this.getTextNodes(function (dict) {
|
809
|
+
dict.nodes.forEach(function (node) {
|
810
|
+
node = node.node;
|
811
|
+
var match = void 0;
|
812
|
+
while ((match = regex.exec(node.textContent)) !== null && match[matchIdx] !== '') {
|
813
|
+
if (_this5.opt.separateGroups) {
|
814
|
+
node = _this5.separateGroups(node, match, matchIdx, filterCb, eachCb);
|
815
|
+
} else {
|
816
|
+
if (!filterCb(match[matchIdx], node)) {
|
817
|
+
continue;
|
818
|
+
}
|
819
|
+
var pos = match.index;
|
820
|
+
if (matchIdx !== 0) {
|
821
|
+
for (var i = 1; i < matchIdx; i++) {
|
822
|
+
pos += match[i].length;
|
823
|
+
}
|
824
|
+
}
|
825
|
+
node = _this5.wrapGroups(node, pos, match[matchIdx].length, eachCb);
|
826
|
+
}
|
827
|
+
regex.lastIndex = 0;
|
828
|
+
}
|
829
|
+
});
|
830
|
+
endCb();
|
831
|
+
});
|
832
|
+
}
|
833
|
+
}, {
|
834
|
+
key: 'wrapMatchesAcrossElements',
|
835
|
+
value: function wrapMatchesAcrossElements(regex, ignoreGroups, filterCb, eachCb, endCb) {
|
836
|
+
var _this6 = this;
|
837
|
+
|
838
|
+
var matchIdx = ignoreGroups === 0 ? 0 : ignoreGroups + 1;
|
839
|
+
this.getTextNodes(function (dict) {
|
840
|
+
var match = void 0;
|
841
|
+
while ((match = regex.exec(dict.value)) !== null && match[matchIdx] !== '') {
|
842
|
+
var start = match.index;
|
843
|
+
if (matchIdx !== 0) {
|
844
|
+
for (var i = 1; i < matchIdx; i++) {
|
845
|
+
start += match[i].length;
|
846
|
+
}
|
847
|
+
}
|
848
|
+
var end = start + match[matchIdx].length;
|
849
|
+
_this6.wrapRangeInMappedTextNode(dict, start, end, function (node) {
|
850
|
+
return filterCb(match[matchIdx], node);
|
851
|
+
}, function (node, lastIndex) {
|
852
|
+
regex.lastIndex = lastIndex;
|
853
|
+
eachCb(node);
|
854
|
+
});
|
855
|
+
}
|
856
|
+
endCb();
|
857
|
+
});
|
858
|
+
}
|
859
|
+
}, {
|
860
|
+
key: 'wrapRangeFromIndex',
|
861
|
+
value: function wrapRangeFromIndex(ranges, filterCb, eachCb, endCb) {
|
862
|
+
var _this7 = this;
|
863
|
+
|
864
|
+
this.getTextNodes(function (dict) {
|
865
|
+
var originalLength = dict.value.length;
|
866
|
+
ranges.forEach(function (range, counter) {
|
867
|
+
var _checkWhitespaceRange = _this7.checkWhitespaceRanges(range, originalLength, dict.value),
|
868
|
+
start = _checkWhitespaceRange.start,
|
869
|
+
end = _checkWhitespaceRange.end,
|
870
|
+
valid = _checkWhitespaceRange.valid;
|
871
|
+
|
872
|
+
if (valid) {
|
873
|
+
_this7.wrapRangeInMappedTextNode(dict, start, end, function (node) {
|
874
|
+
return filterCb(node, range, dict.value.substring(start, end), counter);
|
875
|
+
}, function (node) {
|
876
|
+
eachCb(node, range);
|
877
|
+
});
|
878
|
+
}
|
879
|
+
});
|
880
|
+
endCb();
|
881
|
+
});
|
882
|
+
}
|
883
|
+
}, {
|
884
|
+
key: 'unwrapMatches',
|
885
|
+
value: function unwrapMatches(node) {
|
886
|
+
var parent = node.parentNode;
|
887
|
+
var docFrag = document.createDocumentFragment();
|
888
|
+
while (node.firstChild) {
|
889
|
+
docFrag.appendChild(node.removeChild(node.firstChild));
|
890
|
+
}
|
891
|
+
parent.replaceChild(docFrag, node);
|
892
|
+
if (!this.ie) {
|
893
|
+
parent.normalize();
|
894
|
+
} else {
|
895
|
+
this.normalizeTextNode(parent);
|
896
|
+
}
|
897
|
+
}
|
898
|
+
}, {
|
899
|
+
key: 'normalizeTextNode',
|
900
|
+
value: function normalizeTextNode(node) {
|
901
|
+
if (!node) {
|
902
|
+
return;
|
903
|
+
}
|
904
|
+
if (node.nodeType === 3) {
|
905
|
+
while (node.nextSibling && node.nextSibling.nodeType === 3) {
|
906
|
+
node.nodeValue += node.nextSibling.nodeValue;
|
907
|
+
node.parentNode.removeChild(node.nextSibling);
|
908
|
+
}
|
909
|
+
} else {
|
910
|
+
this.normalizeTextNode(node.firstChild);
|
911
|
+
}
|
912
|
+
this.normalizeTextNode(node.nextSibling);
|
913
|
+
}
|
914
|
+
}, {
|
915
|
+
key: 'markRegExp',
|
916
|
+
value: function markRegExp(regexp, opt) {
|
917
|
+
var _this8 = this;
|
918
|
+
|
919
|
+
this.opt = opt;
|
920
|
+
this.log('Searching with expression "' + regexp + '"');
|
921
|
+
var totalMatches = 0,
|
922
|
+
fn = 'wrapMatches';
|
923
|
+
var eachCb = function eachCb(element) {
|
924
|
+
totalMatches++;
|
925
|
+
_this8.opt.each(element);
|
926
|
+
};
|
927
|
+
if (this.opt.acrossElements) {
|
928
|
+
fn = 'wrapMatchesAcrossElements';
|
929
|
+
}
|
930
|
+
this[fn](regexp, this.opt.ignoreGroups, function (match, node) {
|
931
|
+
return _this8.opt.filter(node, match, totalMatches);
|
932
|
+
}, eachCb, function () {
|
933
|
+
if (totalMatches === 0) {
|
934
|
+
_this8.opt.noMatch(regexp);
|
935
|
+
}
|
936
|
+
_this8.opt.done(totalMatches);
|
937
|
+
});
|
938
|
+
}
|
939
|
+
}, {
|
940
|
+
key: 'mark',
|
941
|
+
value: function mark(sv, opt) {
|
942
|
+
var _this9 = this;
|
943
|
+
|
944
|
+
this.opt = opt;
|
945
|
+
var totalMatches = 0,
|
946
|
+
fn = 'wrapMatches';
|
947
|
+
|
948
|
+
var _getSeparatedKeywords = this.getSeparatedKeywords(typeof sv === 'string' ? [sv] : sv),
|
949
|
+
kwArr = _getSeparatedKeywords.keywords,
|
950
|
+
kwArrLen = _getSeparatedKeywords.length,
|
951
|
+
handler = function handler(kw) {
|
952
|
+
var regex = new RegExpCreator(_this9.opt).create(kw);
|
953
|
+
var matches = 0;
|
954
|
+
_this9.log('Searching with expression "' + regex + '"');
|
955
|
+
_this9[fn](regex, 1, function (term, node) {
|
956
|
+
return _this9.opt.filter(node, kw, totalMatches, matches);
|
957
|
+
}, function (element) {
|
958
|
+
matches++;
|
959
|
+
totalMatches++;
|
960
|
+
_this9.opt.each(element);
|
961
|
+
}, function () {
|
962
|
+
if (matches === 0) {
|
963
|
+
_this9.opt.noMatch(kw);
|
964
|
+
}
|
965
|
+
if (kwArr[kwArrLen - 1] === kw) {
|
966
|
+
_this9.opt.done(totalMatches);
|
967
|
+
} else {
|
968
|
+
handler(kwArr[kwArr.indexOf(kw) + 1]);
|
969
|
+
}
|
970
|
+
});
|
971
|
+
};
|
972
|
+
|
973
|
+
if (this.opt.acrossElements) {
|
974
|
+
fn = 'wrapMatchesAcrossElements';
|
975
|
+
}
|
976
|
+
if (kwArrLen === 0) {
|
977
|
+
this.opt.done(totalMatches);
|
978
|
+
} else {
|
979
|
+
handler(kwArr[0]);
|
980
|
+
}
|
981
|
+
}
|
982
|
+
}, {
|
983
|
+
key: 'markRanges',
|
984
|
+
value: function markRanges(rawRanges, opt) {
|
985
|
+
var _this10 = this;
|
986
|
+
|
987
|
+
this.opt = opt;
|
988
|
+
var totalMatches = 0,
|
989
|
+
ranges = this.checkRanges(rawRanges);
|
990
|
+
if (ranges && ranges.length) {
|
991
|
+
this.log('Starting to mark with the following ranges: ' + JSON.stringify(ranges));
|
992
|
+
this.wrapRangeFromIndex(ranges, function (node, range, match, counter) {
|
993
|
+
return _this10.opt.filter(node, range, match, counter);
|
994
|
+
}, function (element, range) {
|
995
|
+
totalMatches++;
|
996
|
+
_this10.opt.each(element, range);
|
997
|
+
}, function () {
|
998
|
+
_this10.opt.done(totalMatches);
|
999
|
+
});
|
1000
|
+
} else {
|
1001
|
+
this.opt.done(totalMatches);
|
1002
|
+
}
|
1003
|
+
}
|
1004
|
+
}, {
|
1005
|
+
key: 'unmark',
|
1006
|
+
value: function unmark(opt) {
|
1007
|
+
var _this11 = this;
|
1008
|
+
|
1009
|
+
this.opt = opt;
|
1010
|
+
var sel = this.opt.element ? this.opt.element : '*';
|
1011
|
+
sel += '[data-markjs]';
|
1012
|
+
if (this.opt.className) {
|
1013
|
+
sel += '.' + this.opt.className;
|
1014
|
+
}
|
1015
|
+
this.log('Removal selector "' + sel + '"');
|
1016
|
+
this.iterator.forEachNode(NodeFilter.SHOW_ELEMENT, function (node) {
|
1017
|
+
_this11.unwrapMatches(node);
|
1018
|
+
}, function (node) {
|
1019
|
+
var matchesSel = DOMIterator.matches(node, sel),
|
1020
|
+
matchesExclude = _this11.matchesExclude(node);
|
1021
|
+
if (!matchesSel || matchesExclude) {
|
1022
|
+
return NodeFilter.FILTER_REJECT;
|
1023
|
+
} else {
|
1024
|
+
return NodeFilter.FILTER_ACCEPT;
|
1025
|
+
}
|
1026
|
+
}, this.opt.done);
|
1027
|
+
}
|
1028
|
+
}, {
|
1029
|
+
key: 'opt',
|
1030
|
+
set: function set$$1(val) {
|
1031
|
+
this._opt = _extends({}, {
|
1032
|
+
'element': '',
|
1033
|
+
'className': '',
|
1034
|
+
'exclude': [],
|
1035
|
+
'iframes': false,
|
1036
|
+
'iframesTimeout': 5000,
|
1037
|
+
'separateWordSearch': true,
|
1038
|
+
'acrossElements': false,
|
1039
|
+
'ignoreGroups': 0,
|
1040
|
+
'each': function each() {},
|
1041
|
+
'noMatch': function noMatch() {},
|
1042
|
+
'filter': function filter() {
|
1043
|
+
return true;
|
1044
|
+
},
|
1045
|
+
'done': function done() {},
|
1046
|
+
'debug': false,
|
1047
|
+
'log': window.console
|
1048
|
+
}, val);
|
1049
|
+
},
|
1050
|
+
get: function get$$1() {
|
1051
|
+
return this._opt;
|
1052
|
+
}
|
1053
|
+
}, {
|
1054
|
+
key: 'iterator',
|
1055
|
+
get: function get$$1() {
|
1056
|
+
return new DOMIterator(this.ctx, this.opt.iframes, this.opt.exclude, this.opt.iframesTimeout);
|
1057
|
+
}
|
1058
|
+
}]);
|
1059
|
+
return Mark;
|
1060
|
+
}();
|
1061
|
+
|
1062
|
+
$.fn.mark = function (sv, opt) {
|
1063
|
+
new Mark(this.get()).mark(sv, opt);
|
1064
|
+
return this;
|
1065
|
+
};
|
1066
|
+
$.fn.markRegExp = function (regexp, opt) {
|
1067
|
+
new Mark(this.get()).markRegExp(regexp, opt);
|
1068
|
+
return this;
|
1069
|
+
};
|
1070
|
+
$.fn.markRanges = function (ranges, opt) {
|
1071
|
+
new Mark(this.get()).markRanges(ranges, opt);
|
1072
|
+
return this;
|
1073
|
+
};
|
1074
|
+
$.fn.unmark = function (opt) {
|
1075
|
+
new Mark(this.get()).unmark(opt);
|
1076
|
+
return this;
|
1077
|
+
};
|
1078
|
+
|
1079
|
+
return $;
|
1080
|
+
|
1081
|
+
})));
|