govuk_tech_docs 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
})));
|