@oat-sa/tao-core-ui 1.58.1 → 1.58.2

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.
Files changed (233) hide show
  1. package/dist/actionbar.js +386 -395
  2. package/dist/adder.js +21 -19
  3. package/dist/animable/absorbable/absorbable.js +204 -213
  4. package/dist/animable/absorbable/css/absorb.css +1 -0
  5. package/dist/animable/absorbable/css/absorb.css.map +1 -1
  6. package/dist/animable/pulsable/pulsable.js +168 -177
  7. package/dist/autocomplete/css/autocomplete.css +1 -0
  8. package/dist/autocomplete/css/autocomplete.css.map +1 -1
  9. package/dist/autocomplete.js +68 -66
  10. package/dist/badge/badge.js +188 -197
  11. package/dist/badge/css/badge.css +1 -0
  12. package/dist/badge/css/badge.css.map +1 -1
  13. package/dist/breadcrumbs.js +275 -284
  14. package/dist/btngrouper.js +5 -5
  15. package/dist/bulkActionPopup.js +490 -495
  16. package/dist/button.js +283 -291
  17. package/dist/cascadingComboBox.js +249 -258
  18. package/dist/ckeditor/ckConfigurator.js +26 -19
  19. package/dist/ckeditor/dtdHandler.js +11 -9
  20. package/dist/class/selector.js +441 -450
  21. package/dist/component/resizable.js +1 -1
  22. package/dist/component/windowed.js +285 -294
  23. package/dist/component.js +419 -428
  24. package/dist/contextualPopup.js +417 -426
  25. package/dist/dashboard.js +300 -309
  26. package/dist/datalist.js +753 -762
  27. package/dist/datatable/filterStrategy/multiple.js +1 -1
  28. package/dist/datatable/filterStrategy/single.js +1 -1
  29. package/dist/datatable.js +1527 -1550
  30. package/dist/dateRange/dateRange.js +393 -402
  31. package/dist/datetime/picker.js +665 -672
  32. package/dist/deleter.js +368 -377
  33. package/dist/destination/selector.js +286 -295
  34. package/dist/dialog/alert.js +3 -3
  35. package/dist/dialog/confirm.js +1 -1
  36. package/dist/dialog/confirmDelete.js +216 -225
  37. package/dist/dialog.js +650 -654
  38. package/dist/disabler.js +8 -8
  39. package/dist/documentViewer/providers/pdfViewer/fallback/viewer.js +166 -175
  40. package/dist/documentViewer/providers/pdfViewer/pdfjs/findBar.js +518 -527
  41. package/dist/documentViewer/providers/pdfViewer/pdfjs/pageView.js +380 -389
  42. package/dist/documentViewer/providers/pdfViewer/pdfjs/searchEngine.js +539 -548
  43. package/dist/documentViewer/providers/pdfViewer/pdfjs/viewer.js +369 -378
  44. package/dist/documentViewer/providers/pdfViewer.js +184 -193
  45. package/dist/documentViewer.js +292 -301
  46. package/dist/dropdown.js +383 -392
  47. package/dist/durationer.js +5 -5
  48. package/dist/dynamicComponent.js +597 -598
  49. package/dist/feedback.js +356 -362
  50. package/dist/figure/FigureStateActive.js +117 -108
  51. package/dist/filesender.js +2 -2
  52. package/dist/filter.js +230 -239
  53. package/dist/form/dropdownForm.js +355 -357
  54. package/dist/form/form.js +919 -690
  55. package/dist/form/simpleForm.js +1 -1
  56. package/dist/form/validator/renderer.js +233 -235
  57. package/dist/form/validator/validator.js +257 -189
  58. package/dist/form/widget/definitions.js +1 -1
  59. package/dist/form/widget/providers/checkBox.js +254 -259
  60. package/dist/form/widget/providers/comboBox.js +187 -192
  61. package/dist/form/widget/providers/default.js +8 -9
  62. package/dist/form/widget/providers/hidden.js +170 -179
  63. package/dist/form/widget/providers/hiddenBox.js +262 -267
  64. package/dist/form/widget/providers/radioBox.js +216 -225
  65. package/dist/form/widget/providers/textArea.js +187 -196
  66. package/dist/form/widget/providers/textBox.js +2 -3
  67. package/dist/form/widget/widget.js +473 -475
  68. package/dist/formValidator/formValidator.js +1 -1
  69. package/dist/formValidator/highlighters/message.js +1 -1
  70. package/dist/generis/form/form.js +314 -323
  71. package/dist/generis/validator/validator.js +209 -218
  72. package/dist/generis/widget/checkBox/checkBox.js +218 -227
  73. package/dist/generis/widget/comboBox/comboBox.js +179 -188
  74. package/dist/generis/widget/hiddenBox/hiddenBox.js +220 -229
  75. package/dist/generis/widget/textBox/textBox.js +169 -178
  76. package/dist/generis/widget/widget.js +246 -255
  77. package/dist/groupedComboBox.js +222 -231
  78. package/dist/groupvalidator.js +2 -2
  79. package/dist/highlighter.js +967 -958
  80. package/dist/image/ImgStateActive/helper.js +7 -5
  81. package/dist/image/ImgStateActive/initHelper.js +49 -43
  82. package/dist/image/ImgStateActive/initMediaEditor.js +24 -20
  83. package/dist/image/ImgStateActive/mediaSizer.js +14 -12
  84. package/dist/image/ImgStateActive.js +72 -70
  85. package/dist/incrementer.js +6 -6
  86. package/dist/inplacer.js +6 -6
  87. package/dist/itemButtonList/css/item-button-list.css +1 -0
  88. package/dist/itemButtonList/css/item-button-list.css.map +1 -1
  89. package/dist/itemButtonList.js +439 -435
  90. package/dist/keyNavigation/navigableDomElement.js +51 -38
  91. package/dist/keyNavigation/navigator.js +85 -70
  92. package/dist/listbox.js +460 -469
  93. package/dist/liststyler.js +8 -8
  94. package/dist/loadingButton/loadingButton.js +209 -218
  95. package/dist/lock.js +476 -485
  96. package/dist/login/login.js +475 -484
  97. package/dist/maths/calculator/basicCalculator.js +235 -244
  98. package/dist/maths/calculator/calculatorComponent.js +3 -3
  99. package/dist/maths/calculator/core/board.js +772 -781
  100. package/dist/maths/calculator/core/expression.js +476 -485
  101. package/dist/maths/calculator/core/labels.js +228 -237
  102. package/dist/maths/calculator/core/tokenizer.js +1 -1
  103. package/dist/maths/calculator/core/tokens.js +163 -170
  104. package/dist/maths/calculator/plugins/keyboard/templateKeyboard/templateKeyboard.js +244 -253
  105. package/dist/maths/calculator/plugins/screen/simpleScreen/simpleScreen.js +279 -288
  106. package/dist/maths/calculator/scientificCalculator.js +327 -336
  107. package/dist/mediaEditor/mediaEditorComponent.js +238 -245
  108. package/dist/mediaEditor/plugins/mediaAlignment/helper.js +7 -7
  109. package/dist/mediaEditor/plugins/mediaAlignment/mediaAlignmentComponent.js +229 -235
  110. package/dist/mediaEditor/plugins/mediaDimension/mediaDimensionComponent.js +580 -589
  111. package/dist/mediaplayer/players/html5.js +666 -675
  112. package/dist/mediaplayer/players/youtube.js +419 -424
  113. package/dist/mediaplayer/support.js +11 -10
  114. package/dist/mediaplayer/utils/reminder.js +14 -13
  115. package/dist/mediaplayer/utils/timeObserver.js +10 -11
  116. package/dist/mediaplayer/youtubeManager.js +164 -145
  117. package/dist/mediaplayer.js +1565 -1520
  118. package/dist/mediasizer.js +669 -678
  119. package/dist/modal.js +10 -17
  120. package/dist/pageSizeSelector.js +219 -228
  121. package/dist/pagination/providers/pages.js +280 -289
  122. package/dist/pagination/providers/simple.js +192 -201
  123. package/dist/previewer.js +30 -30
  124. package/dist/progressbar.js +4 -4
  125. package/dist/report.js +347 -356
  126. package/dist/resource/filters.js +271 -280
  127. package/dist/resource/list.js +1264 -1273
  128. package/dist/resource/selector.js +865 -874
  129. package/dist/resource/tree.js +1483 -1492
  130. package/dist/resourcemgr/fileBrowser.js +564 -569
  131. package/dist/resourcemgr/filePreview.js +16 -16
  132. package/dist/resourcemgr/fileSelector.js +515 -524
  133. package/dist/resourcemgr/util/updatePermissions.js +2 -2
  134. package/dist/resourcemgr.js +306 -315
  135. package/dist/searchModal/advancedSearch.js +796 -767
  136. package/dist/searchModal.js +114 -91
  137. package/dist/switch/switch.js +298 -307
  138. package/dist/tabs.js +598 -575
  139. package/dist/taskQueue/status.js +312 -321
  140. package/dist/taskQueue/table.js +375 -384
  141. package/dist/taskQueue/taskQueueModel.js +488 -472
  142. package/dist/taskQueueButton/taskable.js +264 -273
  143. package/dist/taskQueueButton/treeButton.js +189 -198
  144. package/dist/themeLoader.js +24 -23
  145. package/dist/themes.js +1 -1
  146. package/dist/toggler.js +3 -3
  147. package/dist/tooltip.js +295 -304
  148. package/dist/transformer.js +2 -2
  149. package/dist/tristateCheckboxGroup.js +311 -320
  150. package/dist/uploader.js +687 -696
  151. package/dist/validator/Report.js +1 -1
  152. package/dist/validator/Validator.js +3 -3
  153. package/dist/validator/validators.js +9 -9
  154. package/dist/validator.js +240 -230
  155. package/dist/waitForMedia.js +1 -1
  156. package/package.json +3 -3
  157. package/src/animable/absorbable/css/absorb.css +1 -0
  158. package/src/animable/absorbable/css/absorb.css.map +1 -1
  159. package/src/autocomplete/css/autocomplete.css +1 -0
  160. package/src/autocomplete/css/autocomplete.css.map +1 -1
  161. package/src/badge/css/badge.css +1 -0
  162. package/src/badge/css/badge.css.map +1 -1
  163. package/src/ckeditor/ckConfigurator.js +4 -0
  164. package/src/itemButtonList/css/item-button-list.css +1 -0
  165. package/src/itemButtonList/css/item-button-list.css.map +1 -1
  166. package/src/.DS_Store +0 -0
  167. package/src/css/basic.css +0 -7826
  168. package/src/css/basic.css.map +0 -1
  169. package/src/css/ckeditor/skins/tao/css/dialog.css +0 -950
  170. package/src/css/ckeditor/skins/tao/css/dialog.css.map +0 -1
  171. package/src/css/ckeditor/skins/tao/css/editor.css +0 -1850
  172. package/src/css/ckeditor/skins/tao/css/editor.css.map +0 -1
  173. package/src/scss/.DS_Store +0 -0
  174. package/src/scss/basic.scss +0 -16
  175. package/src/scss/ckeditor/skins/tao/scss/dialog.scss +0 -763
  176. package/src/scss/ckeditor/skins/tao/scss/editor.scss +0 -111
  177. package/src/scss/ckeditor/skins/tao/scss/inc/_ck-icons.scss +0 -59
  178. package/src/scss/ckeditor/skins/tao/scss/inc/_colorpanel.scss +0 -118
  179. package/src/scss/ckeditor/skins/tao/scss/inc/_elementspath.scss +0 -69
  180. package/src/scss/ckeditor/skins/tao/scss/inc/_mainui.scss +0 -194
  181. package/src/scss/ckeditor/skins/tao/scss/inc/_menu.scss +0 -181
  182. package/src/scss/ckeditor/skins/tao/scss/inc/_panel.scss +0 -200
  183. package/src/scss/ckeditor/skins/tao/scss/inc/_presets.scss +0 -32
  184. package/src/scss/ckeditor/skins/tao/scss/inc/_reset.scss +0 -101
  185. package/src/scss/ckeditor/skins/tao/scss/inc/_richcombo.scss +0 -213
  186. package/src/scss/ckeditor/skins/tao/scss/inc/_tao.scss +0 -59
  187. package/src/scss/ckeditor/skins/tao/scss/inc/_toolbar.scss +0 -301
  188. package/src/scss/font/source-sans-pro/source-sans-pro-italic.eot +0 -0
  189. package/src/scss/font/source-sans-pro/source-sans-pro-italic.eot.b64 +0 -1
  190. package/src/scss/font/source-sans-pro/source-sans-pro-italic.woff +0 -0
  191. package/src/scss/font/source-sans-pro/source-sans-pro-italic.woff.b64 +0 -1
  192. package/src/scss/font/source-sans-pro/source-sans-pro-regular.eot +0 -0
  193. package/src/scss/font/source-sans-pro/source-sans-pro-regular.eot.b64 +0 -1
  194. package/src/scss/font/source-sans-pro/source-sans-pro-regular.woff +0 -0
  195. package/src/scss/font/source-sans-pro/source-sans-pro-regular.woff.b64 +0 -1
  196. package/src/scss/font/source-sans-pro/source-sans-pro-semibold-italic.eot +0 -0
  197. package/src/scss/font/source-sans-pro/source-sans-pro-semibold-italic.eot.b64 +0 -1
  198. package/src/scss/font/source-sans-pro/source-sans-pro-semibold-italic.woff +0 -0
  199. package/src/scss/font/source-sans-pro/source-sans-pro-semibold-italic.woff.b64 +0 -1
  200. package/src/scss/font/source-sans-pro/source-sans-pro-semibold.eot +0 -0
  201. package/src/scss/font/source-sans-pro/source-sans-pro-semibold.eot.b64 +0 -1
  202. package/src/scss/font/source-sans-pro/source-sans-pro-semibold.woff +0 -0
  203. package/src/scss/font/source-sans-pro/source-sans-pro-semibold.woff.b64 +0 -1
  204. package/src/scss/font/tao/tao.eot +0 -0
  205. package/src/scss/font/tao/tao.svg +0 -235
  206. package/src/scss/font/tao/tao.ttf +0 -0
  207. package/src/scss/font/tao/tao.woff +0 -0
  208. package/src/scss/inc/_base.scss +0 -496
  209. package/src/scss/inc/_bootstrap.scss +0 -6
  210. package/src/scss/inc/_buttons.scss +0 -114
  211. package/src/scss/inc/_colors.scss +0 -88
  212. package/src/scss/inc/_feedback.scss +0 -150
  213. package/src/scss/inc/_flex-grid.scss +0 -15
  214. package/src/scss/inc/_fonts.scss +0 -4
  215. package/src/scss/inc/_forms.scss +0 -827
  216. package/src/scss/inc/_functions.scss +0 -283
  217. package/src/scss/inc/_grid.scss +0 -66
  218. package/src/scss/inc/_jquery.nouislider.scss +0 -254
  219. package/src/scss/inc/_normalize.scss +0 -528
  220. package/src/scss/inc/_report.scss +0 -68
  221. package/src/scss/inc/_secondary-properties.scss +0 -89
  222. package/src/scss/inc/_select2.scss +0 -634
  223. package/src/scss/inc/_toolbars.scss +0 -155
  224. package/src/scss/inc/_tooltip.scss +0 -312
  225. package/src/scss/inc/_variables.scss +0 -21
  226. package/src/scss/inc/base/_highlight.scss +0 -5
  227. package/src/scss/inc/base/_list-style.scss +0 -59
  228. package/src/scss/inc/base/_svg.scss +0 -3
  229. package/src/scss/inc/base/_table.scss +0 -63
  230. package/src/scss/inc/fonts/_source-sans-pro.scss +0 -29
  231. package/src/scss/inc/fonts/_tao-icon-classes.scss +0 -226
  232. package/src/scss/inc/fonts/_tao-icon-def.scss +0 -12
  233. package/src/scss/inc/fonts/_tao-icon-vars.scss +0 -240
@@ -1,1199 +1,1208 @@
1
1
  define(['lodash', 'jquery'], function (_, $) { 'use strict';
2
2
 
3
- _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
4
- $ = $ && Object.prototype.hasOwnProperty.call($, 'default') ? $['default'] : $;
5
-
3
+ _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _;
4
+ $ = $ && Object.prototype.hasOwnProperty.call($, 'default') ? $['default'] : $;
5
+
6
+ function _typeof(obj) {
7
+ "@babel/helpers - typeof";
8
+
9
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
10
+ return typeof obj;
11
+ } : function (obj) {
12
+ return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
13
+ }, _typeof(obj);
14
+ }
15
+
16
+ /**
17
+ * Data attribute used to logically group the wrapping nodes into a single selection
18
+ * @type {string}
19
+ */
20
+
21
+ var GROUP_ATTR = 'data-hl-group';
22
+ /**
23
+ * Children of those nodes types cannot be highlighted
24
+ * @type {string[]}
25
+ */
26
+
27
+ var defaultBlackList = ['textarea', 'math', 'script', '.select2-container'];
28
+ /**
29
+ * @param {Object} options
30
+ * @param {String} options.className - name of the class that will be used by the wrappers tags to highlight text
31
+ * @param {String} options.containerSelector - allows to select the root Node in which highlighting is allowed
32
+ * @param {Array<String>} [options.containersBlackList] - additional blacklist selectors to be added to module instance's blacklist
33
+ * @param {Array<String>} [options.containersWhiteList] - whitelist selectors; supported only in `keepEmptyNodes` mode.
34
+ * Priority of blacklist or whitelist is decided by which selector is closest to the node. If no match found, node is considered whitelisted.
35
+ * @param {Boolean} [options.clearOnClick] - clear single highlight node on click
36
+ * @param {Object} [options.colors] - keys is keeping as the "c" value of storing/restore the highlighters for indexing, values are wrappers class names
37
+ * @param {Boolean} [options.keepEmptyNodes] - retain original dom structure as far as possible and do not remove empty nodes if they were not created by highlighter
38
+ * @returns {Object} - the highlighter instance
39
+ */
40
+
41
+ function highlighter (options) {
42
+ var className = options.className;
43
+ var containerSelector = options.containerSelector;
44
+ var keepEmptyNodes = options.keepEmptyNodes;
45
+ var highlightingClasses = [className]; // Multi-color mode
46
+
47
+ if (options.colors) {
48
+ highlightingClasses = Object.values(options.colors);
49
+ }
6
50
  /**
7
- * This program is free software; you can redistribute it and/or
8
- * modify it under the terms of the GNU General Public License
9
- * as published by the Free Software Foundation; under version 2
10
- * of the License (non-upgradable).
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU General Public License
18
- * along with this program; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
- *
21
- * Copyright (c) 2016-2021 (original work) Open Assessment Technologies SA;
51
+ * list of node selectors which should NOT receive any highlighting from this instance
52
+ * an optional passed-in blacklist is merged with local defaults
53
+ * @type {Array}
22
54
  */
55
+
56
+
57
+ var containersBlackList = _.union(defaultBlackList, options.containersBlackList);
58
+
59
+ var containersBlackListSelector = containersBlackList.join(', ');
60
+ var containersWhiteListSelector = null;
61
+ var containersBlackAndWhiteListSelector = containersBlackListSelector;
62
+
63
+ if (options.keepEmptyNodes && options.containersWhiteList) {
64
+ containersWhiteListSelector = options.containersWhiteList.join(', ');
65
+ containersBlackAndWhiteListSelector = _.union(containersBlackList, options.containersWhiteList).join(', ');
66
+ }
23
67
  /**
24
- * Data attribute used to logically group the wrapping nodes into a single selection
25
- * @type {string}
68
+ * used in recursive loops to decide if we should wrap or not the current node
69
+ * @type {boolean}
26
70
  */
27
71
 
28
- var GROUP_ATTR = 'data-hl-group';
72
+
73
+ var isWrapping = false;
29
74
  /**
30
- * Children of those nodes types cannot be highlighted
31
- * @type {string[]}
75
+ * performance improvement to break out of a potentially big recursive loop once the wrapping has ended
76
+ * @type {boolean}
32
77
  */
33
78
 
34
- var defaultBlackList = ['textarea', 'math', 'script', '.select2-container'];
79
+ var hasWrapped = false;
35
80
  /**
36
- * @param {Object} options
37
- * @param {String} options.className - name of the class that will be used by the wrappers tags to highlight text
38
- * @param {String} options.containerSelector - allows to select the root Node in which highlighting is allowed
39
- * @param {Array<String>} [options.containersBlackList] - additional blacklist selectors to be added to module instance's blacklist
40
- * @param {Array<String>} [options.containersWhiteList] - whitelist selectors; supported only in `keepEmptyNodes` mode.
41
- * Priority of blacklist or whitelist is decided by which selector is closest to the node. If no match found, node is considered whitelisted.
42
- * @param {Boolean} [options.clearOnClick] - clear single highlight node on click
43
- * @param {Object} [options.colors] - keys is keeping as the "c" value of storing/restore the highlighters for indexing, values are wrappers class names
44
- * @param {Boolean} [options.keepEmptyNodes] - retain original dom structure as far as possible and do not remove empty nodes if they were not created by highlighter
45
- * @returns {Object} - the highlighter instance
81
+ * used in recursive loops to assign a group Id to the current wrapped node
82
+ * @type {number}
46
83
  */
47
84
 
48
- function highlighter (options) {
49
- var className = options.className;
50
- var containerSelector = options.containerSelector;
51
- var keepEmptyNodes = options.keepEmptyNodes;
52
- let highlightingClasses = [className]; // Multi-color mode
53
-
54
- if (options.colors) {
55
- highlightingClasses = Object.values(options.colors);
56
- }
57
- /**
58
- * list of node selectors which should NOT receive any highlighting from this instance
59
- * an optional passed-in blacklist is merged with local defaults
60
- * @type {Array}
61
- */
62
-
63
-
64
- var containersBlackList = _.union(defaultBlackList, options.containersBlackList);
65
-
66
- var containersBlackListSelector = containersBlackList.join(', ');
67
- var containersWhiteListSelector = null;
68
- var containersBlackAndWhiteListSelector = containersBlackListSelector;
69
-
70
- if (options.keepEmptyNodes && options.containersWhiteList) {
71
- containersWhiteListSelector = options.containersWhiteList.join(', ');
72
- containersBlackAndWhiteListSelector = _.union(containersBlackList, options.containersWhiteList).join(', ');
73
- }
74
- /**
75
- * used in recursive loops to decide if we should wrap or not the current node
76
- * @type {boolean}
77
- */
78
-
79
-
80
- var isWrapping = false;
81
- /**
82
- * performance improvement to break out of a potentially big recursive loop once the wrapping has ended
83
- * @type {boolean}
84
- */
85
-
86
- var hasWrapped = false;
87
- /**
88
- * used in recursive loops to assign a group Id to the current wrapped node
89
- * @type {number}
90
- */
91
-
92
- var currentGroupId;
93
- /**
94
- * used in recursive loops to build the index of text nodes
95
- * @type {number}
96
- */
85
+ var currentGroupId;
86
+ /**
87
+ * used in recursive loops to build the index of text nodes
88
+ * @type {number}
89
+ */
97
90
 
98
- var textNodesIndex;
99
- /**
100
- * Returns the node in which highlighting is allowed
101
- * @returns {Element}
102
- */
91
+ var textNodesIndex;
92
+ /**
93
+ * Returns the node in which highlighting is allowed
94
+ * @returns {Element}
95
+ */
103
96
 
104
- function getContainer() {
105
- return $(containerSelector).get(0);
106
- }
107
- /**
108
- * Returns all highlighted nodes, excluding any inside blacklisted elements
109
- * @returns {JQuery<HTMLElement>}
110
- */
97
+ function getContainer() {
98
+ return $(containerSelector).get(0);
99
+ }
100
+ /**
101
+ * Returns all highlighted nodes, excluding any inside blacklisted elements
102
+ * @returns {JQuery<HTMLElement>}
103
+ */
111
104
 
112
105
 
113
- function getHighlightedNodes() {
114
- return $(containerSelector).find(`.${highlightingClasses.join(',.')}`).filter((i, node) => !isBlacklisted(node));
115
- }
116
- /**
117
- * Attach data to wrapper node.
118
- * Use it when deleting this highlight to know if highlight content should be merged with neighbour text nodes or not.
119
- * Use it when building/restoring index to know if restored highlight content should be split off neighbour text node or not.
120
- * Needed to keep markup the same as it was before highlighting.
121
- * @param {HTMLElement} node
122
- * @param {Boolean} beforeWasSplit
123
- * @param {Boolean} afterWasSplit
124
- */
106
+ function getHighlightedNodes() {
107
+ return $(containerSelector).find(".".concat(highlightingClasses.join(',.'))).filter(function (i, node) {
108
+ return !isBlacklisted(node);
109
+ });
110
+ }
111
+ /**
112
+ * Attach data to wrapper node.
113
+ * Use it when deleting this highlight to know if highlight content should be merged with neighbour text nodes or not.
114
+ * Use it when building/restoring index to know if restored highlight content should be split off neighbour text node or not.
115
+ * Needed to keep markup the same as it was before highlighting.
116
+ * @param {HTMLElement} node
117
+ * @param {Boolean} beforeWasSplit
118
+ * @param {Boolean} afterWasSplit
119
+ */
125
120
 
126
121
 
127
- function addSplitData(node, beforeWasSplit, afterWasSplit) {
128
- node.dataset.beforeWasSplit = beforeWasSplit;
129
- node.dataset.afterWasSplit = afterWasSplit;
130
- }
131
- /**
132
- * Highlight all text nodes within each given range
133
- * @param {Range[]} ranges - array of ranges to highlight, may be given by the helper selector.getAllRanges()
134
- */
122
+ function addSplitData(node, beforeWasSplit, afterWasSplit) {
123
+ node.dataset.beforeWasSplit = beforeWasSplit;
124
+ node.dataset.afterWasSplit = afterWasSplit;
125
+ }
126
+ /**
127
+ * Highlight all text nodes within each given range
128
+ * @param {Range[]} ranges - array of ranges to highlight, may be given by the helper selector.getAllRanges()
129
+ */
135
130
 
136
131
 
137
- function highlightRanges(ranges) {
138
- ranges.forEach(function (range) {
139
- var rangeInfos;
132
+ function highlightRanges(ranges) {
133
+ ranges.forEach(function (range) {
134
+ var rangeInfos;
140
135
 
141
- if (isRangeValid(range)) {
142
- currentGroupId = getAvailableGroupId(); // easy peasy: highlighting a plain text without any DOM nodes
143
- // NOTE: The condition checks the whole node content and not a selected content in a given range, that allows to wrap whitespace
136
+ if (isRangeValid(range)) {
137
+ currentGroupId = getAvailableGroupId(); // easy peasy: highlighting a plain text without any DOM nodes
138
+ // NOTE: The condition checks the whole node content and not a selected content in a given range, that allows to wrap whitespace
144
139
 
145
- if (isWrappable(range.commonAncestorContainer) && !isWrappingNode(range.commonAncestorContainer.parentNode)) {
146
- const wrapperNode = getWrapper(currentGroupId);
140
+ if (isWrappable(range.commonAncestorContainer) && !isWrappingNode(range.commonAncestorContainer.parentNode)) {
141
+ var wrapperNode = getWrapper(currentGroupId);
147
142
 
148
- if (!keepEmptyNodes) {
149
- range.surroundContents(wrapperNode);
150
- } else {
151
- addSplitData(wrapperNode, range.startOffset > 0, range.endOffset < range.commonAncestorContainer.length);
152
- rangeSurroundContentsNoEmptyNodes(range, wrapperNode);
153
- }
154
- } else if (isWrappable(range.commonAncestorContainer) && isWrappingNode(range.commonAncestorContainer.parentNode) && range.commonAncestorContainer.parentNode !== className) {
155
- highlightContainerNodes(range.commonAncestorContainer, className, range, currentGroupId); // now the fun stuff: highlighting a mix of text and DOM nodes
143
+ if (!keepEmptyNodes) {
144
+ range.surroundContents(wrapperNode);
156
145
  } else {
157
- rangeInfos = {
158
- startNode: isElement(range.startContainer) ? range.startContainer.childNodes[range.startOffset] : range.startContainer,
159
- startNodeContainer: range.startContainer,
160
- startOffset: range.startOffset,
161
- endNode: isElement(range.endContainer) && range.endOffset > 0 ? range.endContainer.childNodes[range.endOffset - 1] : range.endContainer,
162
- endNodeContainer: range.endContainer,
163
- endOffset: range.endOffset,
164
- commonRange: range
165
- };
166
- isWrapping = false;
167
- hasWrapped = false;
168
- wrapTextNodesInRange(range.commonAncestorContainer, rangeInfos);
146
+ addSplitData(wrapperNode, range.startOffset > 0, range.endOffset < range.commonAncestorContainer.length);
147
+ rangeSurroundContentsNoEmptyNodes(range, wrapperNode);
169
148
  }
149
+ } else if (isWrappable(range.commonAncestorContainer) && isWrappingNode(range.commonAncestorContainer.parentNode) && range.commonAncestorContainer.parentNode !== className) {
150
+ highlightContainerNodes(range.commonAncestorContainer, className, range, currentGroupId); // now the fun stuff: highlighting a mix of text and DOM nodes
151
+ } else {
152
+ rangeInfos = {
153
+ startNode: isElement(range.startContainer) ? range.startContainer.childNodes[range.startOffset] : range.startContainer,
154
+ startNodeContainer: range.startContainer,
155
+ startOffset: range.startOffset,
156
+ endNode: isElement(range.endContainer) && range.endOffset > 0 ? range.endContainer.childNodes[range.endOffset - 1] : range.endContainer,
157
+ endNodeContainer: range.endContainer,
158
+ endOffset: range.endOffset,
159
+ commonRange: range
160
+ };
161
+ isWrapping = false;
162
+ hasWrapped = false;
163
+ wrapTextNodesInRange(range.commonAncestorContainer, rangeInfos);
170
164
  }
165
+ }
171
166
 
172
- if (!keepEmptyNodes) {
173
- // clean up the markup after wrapping...
174
- range.commonAncestorContainer.normalize();
175
- }
167
+ if (!keepEmptyNodes) {
168
+ // clean up the markup after wrapping...
169
+ range.commonAncestorContainer.normalize();
170
+ }
176
171
 
177
- currentGroupId = 0;
178
- isWrapping = false;
179
- reindexGroups(getContainer());
180
- mergeAdjacentWrappingNodes(getContainer());
181
- unWrapEmptyHighlights();
182
- });
172
+ currentGroupId = 0;
173
+ isWrapping = false;
174
+ reindexGroups(getContainer());
175
+ mergeAdjacentWrappingNodes(getContainer());
176
+ unWrapEmptyHighlights();
177
+ });
183
178
 
184
- if (options.clearOnClick) {
185
- $(containerSelector + ' .' + className).off('click').on('click', clearSingleHighlight);
186
- }
179
+ if (options.clearOnClick) {
180
+ $(containerSelector + ' .' + className).off('click').on('click', clearSingleHighlight);
187
181
  }
188
- /**
189
- * Check if a range is valid
190
- * @param {Range} range
191
- * @returns {boolean}
192
- */
182
+ }
183
+ /**
184
+ * Check if a range is valid
185
+ * @param {Range} range
186
+ * @returns {boolean}
187
+ */
193
188
 
194
189
 
195
- function isRangeValid(range) {
196
- var rangeInContainer;
190
+ function isRangeValid(range) {
191
+ var rangeInContainer;
197
192
 
198
- try {
199
- rangeInContainer = $.contains(getContainer(), range.commonAncestorContainer) || getContainer().isSameNode(range.commonAncestorContainer);
200
- return rangeInContainer && !range.collapsed;
201
- } catch (e) {
202
- return false;
203
- }
193
+ try {
194
+ rangeInContainer = $.contains(getContainer(), range.commonAncestorContainer) || getContainer().isSameNode(range.commonAncestorContainer);
195
+ return rangeInContainer && !range.collapsed;
196
+ } catch (e) {
197
+ return false;
204
198
  }
205
- /**
206
- * Core wrapping function. Traverse the DOM tree and highlight (= wraps) all text nodes within the given range.
207
- * Recursive.
208
- *
209
- * @param {Node} rootNode - top of the node hierarchy in which text nodes will be searched
210
- * @param {Object} rangeInfos
211
- * @param {Node} rangeInfos.startNode - node on which the selection starts
212
- * @param {Node} rangeInfos.startNodeContainer - container of the startNode, or the start node itself in case of text nodes
213
- * @param {number} rangeInfos.startOffset - same as range.startOffset, but not read-only to allow override
214
- * @param {Node} rangeInfos.endNode - node on which the selection ends
215
- * @param {Node} rangeInfos.endNodeContainer - container of the endNode, or the end node itself in case of text nodes
216
- * @param {number} rangeInfos.endOffset - same as range.endOffset, but not read-only to allow override
217
- */
199
+ }
200
+ /**
201
+ * Core wrapping function. Traverse the DOM tree and highlight (= wraps) all text nodes within the given range.
202
+ * Recursive.
203
+ *
204
+ * @param {Node} rootNode - top of the node hierarchy in which text nodes will be searched
205
+ * @param {Object} rangeInfos
206
+ * @param {Node} rangeInfos.startNode - node on which the selection starts
207
+ * @param {Node} rangeInfos.startNodeContainer - container of the startNode, or the start node itself in case of text nodes
208
+ * @param {number} rangeInfos.startOffset - same as range.startOffset, but not read-only to allow override
209
+ * @param {Node} rangeInfos.endNode - node on which the selection ends
210
+ * @param {Node} rangeInfos.endNodeContainer - container of the endNode, or the end node itself in case of text nodes
211
+ * @param {number} rangeInfos.endOffset - same as range.endOffset, but not read-only to allow override
212
+ */
218
213
 
219
214
 
220
- function wrapTextNodesInRange(rootNode, rangeInfos) {
221
- var childNodes = rootNode.childNodes;
222
- var currentNode, i;
223
- var splitDatas = [];
215
+ function wrapTextNodesInRange(rootNode, rangeInfos) {
216
+ var childNodes = rootNode.childNodes;
217
+ var currentNode, i;
218
+ var splitDatas = [];
224
219
 
225
- for (i = 0; i < childNodes.length; i++) {
226
- if (hasWrapped) {
227
- break;
228
- }
220
+ for (i = 0; i < childNodes.length; i++) {
221
+ if (hasWrapped) {
222
+ break;
223
+ }
229
224
 
230
- currentNode = childNodes[i];
225
+ currentNode = childNodes[i];
231
226
 
232
- if (isBlacklisted(currentNode)) {
233
- if (isElement(currentNode)) {
234
- //go deeper in case a descendant of the current blacklisted is whitelisted
235
- wrapTextNodesInRange(currentNode, rangeInfos);
236
- }
237
- } else {
238
- const isCurrentNodeTextInsideOfAnotherHighlightingWrapper = isText(currentNode) && isWrappingNode(currentNode.parentNode) && currentNode.parentNode.className !== className;
227
+ if (isBlacklisted(currentNode)) {
228
+ if (isElement(currentNode)) {
229
+ //go deeper in case a descendant of the current blacklisted is whitelisted
230
+ wrapTextNodesInRange(currentNode, rangeInfos);
231
+ }
232
+ } else {
233
+ var isCurrentNodeTextInsideOfAnotherHighlightingWrapper = isText(currentNode) && isWrappingNode(currentNode.parentNode) && currentNode.parentNode.className !== className;
239
234
 
240
- if (isCurrentNodeTextInsideOfAnotherHighlightingWrapper) {
241
- const internalRange = new Range();
242
- internalRange.selectNodeContents(currentNode);
235
+ if (isCurrentNodeTextInsideOfAnotherHighlightingWrapper) {
236
+ var internalRange = new Range();
237
+ internalRange.selectNodeContents(currentNode);
243
238
 
244
- if (rangeInfos.startNode === currentNode) {
245
- internalRange.setStart(currentNode, rangeInfos.startOffset);
246
- }
239
+ if (rangeInfos.startNode === currentNode) {
240
+ internalRange.setStart(currentNode, rangeInfos.startOffset);
241
+ }
247
242
 
248
- if (rangeInfos.endNode === currentNode) {
249
- internalRange.setEnd(currentNode, rangeInfos.endOffset);
250
- }
243
+ if (rangeInfos.endNode === currentNode) {
244
+ internalRange.setEnd(currentNode, rangeInfos.endOffset);
245
+ }
251
246
 
252
- const isNodeInRange = rangeInfos.commonRange.isPointInRange(currentNode, internalRange.endOffset); // Apply new highlighting color only for selected nodes
247
+ var isNodeInRange = rangeInfos.commonRange.isPointInRange(currentNode, internalRange.endOffset); // Apply new highlighting color only for selected nodes
253
248
 
254
- if (isNodeInRange) {
249
+ if (isNodeInRange) {
250
+ isWrapping = true;
251
+ highlightContainerNodes(currentNode, className, internalRange, currentGroupId);
252
+ }
253
+ } else {
254
+ // split current node in case the wrapping start/ends on a partially selected text node
255
+ if (currentNode.isSameNode(rangeInfos.startNode)) {
256
+ if (isText(rangeInfos.startNodeContainer) && rangeInfos.startOffset !== 0) {
257
+ // we defer the wrapping to the next iteration of the loop
258
+ //end of node should be highlighted
259
+ rangeInfos.startNode = currentNode.splitText(rangeInfos.startOffset);
260
+ rangeInfos.startOffset = 0;
261
+ splitDatas.push({
262
+ node: rangeInfos.startNode,
263
+ beforeWasSplit: true,
264
+ afterWasSplit: false
265
+ });
266
+ } else {
267
+ //whole node should be highlighted
255
268
  isWrapping = true;
256
- highlightContainerNodes(currentNode, className, internalRange, currentGroupId);
269
+ splitDatas.push({
270
+ node: currentNode,
271
+ beforeWasSplit: false,
272
+ afterWasSplit: false
273
+ });
257
274
  }
258
- } else {
259
- // split current node in case the wrapping start/ends on a partially selected text node
260
- if (currentNode.isSameNode(rangeInfos.startNode)) {
261
- if (isText(rangeInfos.startNodeContainer) && rangeInfos.startOffset !== 0) {
262
- // we defer the wrapping to the next iteration of the loop
263
- //end of node should be highlighted
264
- rangeInfos.startNode = currentNode.splitText(rangeInfos.startOffset);
265
- rangeInfos.startOffset = 0;
275
+ }
276
+
277
+ if (currentNode.isSameNode(rangeInfos.endNode) && isText(rangeInfos.endNodeContainer)) {
278
+ if (rangeInfos.endOffset !== 0) {
279
+ if (rangeInfos.endOffset < currentNode.textContent.length) {
280
+ //start of node should be highlighted
281
+ currentNode.splitText(rangeInfos.endOffset);
266
282
  splitDatas.push({
267
- node: rangeInfos.startNode,
268
- beforeWasSplit: true,
269
- afterWasSplit: false
283
+ node: currentNode,
284
+ beforeWasSplit: false,
285
+ afterWasSplit: true
270
286
  });
271
287
  } else {
272
288
  //whole node should be highlighted
273
- isWrapping = true;
274
289
  splitDatas.push({
275
290
  node: currentNode,
276
291
  beforeWasSplit: false,
277
292
  afterWasSplit: false
278
293
  });
279
294
  }
295
+ } else {
296
+ isWrapping = false;
280
297
  }
298
+ } // wrap the current node...
281
299
 
282
- if (currentNode.isSameNode(rangeInfos.endNode) && isText(rangeInfos.endNodeContainer)) {
283
- if (rangeInfos.endOffset !== 0) {
284
- if (rangeInfos.endOffset < currentNode.textContent.length) {
285
- //start of node should be highlighted
286
- currentNode.splitText(rangeInfos.endOffset);
287
- splitDatas.push({
288
- node: currentNode,
289
- beforeWasSplit: false,
290
- afterWasSplit: true
291
- });
292
- } else {
293
- //whole node should be highlighted
294
- splitDatas.push({
295
- node: currentNode,
296
- beforeWasSplit: false,
297
- afterWasSplit: false
298
- });
299
- }
300
- } else {
301
- isWrapping = false;
302
- }
303
- } // wrap the current node...
304
-
305
-
306
- if (isText(currentNode)) {
307
- if (!keepEmptyNodes) {
308
- wrapTextNode(currentNode, currentGroupId);
309
- } else if (willHighlightNotBeEmptyAfterMerge(currentNode)) {
310
- const wrapperNode = wrapTextNode(currentNode, currentGroupId);
311
300
 
312
- if (wrapperNode) {
313
- const splitData = splitDatas.find(d => d.node === currentNode);
314
- addSplitData(wrapperNode, splitData ? splitData.beforeWasSplit : false, splitData ? splitData.afterWasSplit : false);
315
- }
316
- } // ... or continue deeper in the node tree
301
+ if (isText(currentNode)) {
302
+ if (!keepEmptyNodes) {
303
+ wrapTextNode(currentNode, currentGroupId);
304
+ } else if (willHighlightNotBeEmptyAfterMerge(currentNode)) {
305
+ var wrapperNode = wrapTextNode(currentNode, currentGroupId);
317
306
 
318
- } else if (isElement(currentNode)) {
319
- //some selections end at the very start of the next node, we should end wrapping when we reach such node
320
- if (!currentNode.isSameNode(rangeInfos.endNode) || rangeInfos.endOffset > 0) {
321
- wrapTextNodesInRange(currentNode, rangeInfos);
307
+ if (wrapperNode) {
308
+ var splitData = splitDatas.find(function (d) {
309
+ return d.node === currentNode;
310
+ });
311
+ addSplitData(wrapperNode, splitData ? splitData.beforeWasSplit : false, splitData ? splitData.afterWasSplit : false);
322
312
  }
313
+ } // ... or continue deeper in the node tree
314
+
315
+ } else if (isElement(currentNode)) {
316
+ //some selections end at the very start of the next node, we should end wrapping when we reach such node
317
+ if (!currentNode.isSameNode(rangeInfos.endNode) || rangeInfos.endOffset > 0) {
318
+ wrapTextNodesInRange(currentNode, rangeInfos);
323
319
  }
324
320
  }
325
- } // end wrapping ?
321
+ }
322
+ } // end wrapping ?
326
323
 
327
324
 
328
- if (currentNode.isSameNode(rangeInfos.endNode)) {
329
- isWrapping = false;
330
- hasWrapped = true;
331
- break;
332
- }
325
+ if (currentNode.isSameNode(rangeInfos.endNode)) {
326
+ isWrapping = false;
327
+ hasWrapped = true;
328
+ break;
333
329
  }
334
330
  }
335
- /**
336
- * Restructure content of the highlighted wrapper according to the selectedRange
337
- * @param {Node} textNode
338
- * @param {string} activeClass
339
- * @param {Range} selectedRange
340
- * @param {number} currentGroupId
341
- */
331
+ }
332
+ /**
333
+ * Restructure content of the highlighted wrapper according to the selectedRange
334
+ * @param {Node} textNode
335
+ * @param {string} activeClass
336
+ * @param {Range} selectedRange
337
+ * @param {number} currentGroupId
338
+ */
342
339
 
343
340
 
344
- function highlightContainerNodes(textNode, activeClass, selectedRange, currentGroupId) {
345
- const container = textNode.parentNode;
346
- const range = new Range();
347
- range.selectNodeContents(textNode);
348
- const isSelectionCoversNodeStart = range.compareBoundaryPoints(Range.START_TO_START, selectedRange) === 0;
349
- const isSelectionCoversNodeEnd = range.compareBoundaryPoints(Range.END_TO_END, selectedRange) === 0;
350
- /*
351
- There are 4 possible cases selected area is intersected with already highlighted element.
352
- In examples below the border is represents the selection, "yellow" is class name of already highlighted
353
- container, "red" is class name of currently active highlighter
354
- **********************************************************************************************************
355
- 1. The container content is completely selected, so that we only have to change the highlighter class name
356
- Input:
357
- __________________________________________________
358
- | |
359
- |<span class="yellow"> Lorem ipsum dolor sit</span>|
360
- |__________________________________________________|
361
- Output:
362
- <span class="red"> Lorem ipsum dolor sit</span>
363
- **********************************************************************************************************
364
- 2. The container content is partially selected from the begging.
365
- Input:
366
- ______________________________
367
- | |
368
- |<span class="yellow"> Lorem ip|sum dolor sit</span>
369
- |______________________________|
370
- Output:
371
- <span class="red"> Lorem ip</span><span class="yellow">sum dolor sit</span>
372
- **********************************************************************************************************
373
- 3. The container content is partially selected at the end.
374
- Input:
375
- ____________________
376
- | |
377
- <span class="yellow"> Lorem ip|sum dolor sit</span>|
378
- |____________________|
379
- Output:
380
- <span class="yellow"> Lorem ip</span><span class="red">sum dolor sit</span>
381
- **********************************************************************************************************
382
- 4. The container content is partially selected in the middle.
383
- Input:
384
- ___________
385
- | |
386
- <span class="yellow"> Lorem |ipsum dolor| sit</span>
387
- |___________|
388
- Output:
389
- <span class="yellow"> Lorem </span><span class="red">ipsum dolor</span><span class="yellow"> sit</span>
390
- */
391
-
392
- if (isSelectionCoversNodeStart && isSelectionCoversNodeEnd) {
393
- textNode.parentNode.className = activeClass;
394
- } else if (isSelectionCoversNodeStart) {
395
- textNode.splitText(selectedRange.endOffset);
396
- wrapContainerChildNodes(container, 0, activeClass, currentGroupId);
397
- } else if (isSelectionCoversNodeEnd) {
398
- textNode.splitText(selectedRange.startOffset);
399
- wrapContainerChildNodes(container, 1, activeClass, currentGroupId);
400
- } else {
401
- textNode.splitText(selectedRange.startOffset).splitText(selectedRange.endOffset);
402
- wrapContainerChildNodes(container, 1, activeClass, currentGroupId);
403
- }
404
- }
405
- /**
406
- * Wraps all containers text nodes with highlighter element.
407
- * The child node with index given by indexToWrapNode parameter will be wrap with class given by activeClass parameter
408
- * @param {Element} container
409
- * @param {number} indexToWrapNode
410
- * @param {string} activeClass
411
- * @param {number} currentGroupId
341
+ function highlightContainerNodes(textNode, activeClass, selectedRange, currentGroupId) {
342
+ var container = textNode.parentNode;
343
+ var range = new Range();
344
+ range.selectNodeContents(textNode);
345
+ var isSelectionCoversNodeStart = range.compareBoundaryPoints(Range.START_TO_START, selectedRange) === 0;
346
+ var isSelectionCoversNodeEnd = range.compareBoundaryPoints(Range.END_TO_END, selectedRange) === 0;
347
+ /*
348
+ There are 4 possible cases selected area is intersected with already highlighted element.
349
+ In examples below the border is represents the selection, "yellow" is class name of already highlighted
350
+ container, "red" is class name of currently active highlighter
351
+ **********************************************************************************************************
352
+ 1. The container content is completely selected, so that we only have to change the highlighter class name
353
+ Input:
354
+ __________________________________________________
355
+ | |
356
+ |<span class="yellow"> Lorem ipsum dolor sit</span>|
357
+ |__________________________________________________|
358
+ Output:
359
+ <span class="red"> Lorem ipsum dolor sit</span>
360
+ **********************************************************************************************************
361
+ 2. The container content is partially selected from the begging.
362
+ Input:
363
+ ______________________________
364
+ | |
365
+ |<span class="yellow"> Lorem ip|sum dolor sit</span>
366
+ |______________________________|
367
+ Output:
368
+ <span class="red"> Lorem ip</span><span class="yellow">sum dolor sit</span>
369
+ **********************************************************************************************************
370
+ 3. The container content is partially selected at the end.
371
+ Input:
372
+ ____________________
373
+ | |
374
+ <span class="yellow"> Lorem ip|sum dolor sit</span>|
375
+ |____________________|
376
+ Output:
377
+ <span class="yellow"> Lorem ip</span><span class="red">sum dolor sit</span>
378
+ **********************************************************************************************************
379
+ 4. The container content is partially selected in the middle.
380
+ Input:
381
+ ___________
382
+ | |
383
+ <span class="yellow"> Lorem |ipsum dolor| sit</span>
384
+ |___________|
385
+ Output:
386
+ <span class="yellow"> Lorem </span><span class="red">ipsum dolor</span><span class="yellow"> sit</span>
412
387
  */
413
388
 
389
+ if (isSelectionCoversNodeStart && isSelectionCoversNodeEnd) {
390
+ textNode.parentNode.className = activeClass;
391
+ } else if (isSelectionCoversNodeStart) {
392
+ textNode.splitText(selectedRange.endOffset);
393
+ wrapContainerChildNodes(container, 0, activeClass, currentGroupId);
394
+ } else if (isSelectionCoversNodeEnd) {
395
+ textNode.splitText(selectedRange.startOffset);
396
+ wrapContainerChildNodes(container, 1, activeClass, currentGroupId);
397
+ } else {
398
+ textNode.splitText(selectedRange.startOffset).splitText(selectedRange.endOffset);
399
+ wrapContainerChildNodes(container, 1, activeClass, currentGroupId);
400
+ }
401
+ }
402
+ /**
403
+ * Wraps all containers text nodes with highlighter element.
404
+ * The child node with index given by indexToWrapNode parameter will be wrap with class given by activeClass parameter
405
+ * @param {Element} container
406
+ * @param {number} indexToWrapNode
407
+ * @param {string} activeClass
408
+ * @param {number} currentGroupId
409
+ */
414
410
 
415
- function wrapContainerChildNodes(container, indexToWrapNode, activeClass, currentGroupId) {
416
- const containerClass = container.className;
417
- const fragment = new DocumentFragment();
418
- const childNodesLength = container.childNodes.length;
419
- container.childNodes.forEach((node, index) => {
420
- var wrapperNode;
421
-
422
- if (index === indexToWrapNode) {
423
- wrapperNode = wrapNode(node.cloneNode(), activeClass, currentGroupId);
424
- } else {
425
- wrapperNode = wrapNode(node.cloneNode(), containerClass, currentGroupId);
426
- }
427
411
 
428
- fragment.appendChild(wrapperNode);
412
+ function wrapContainerChildNodes(container, indexToWrapNode, activeClass, currentGroupId) {
413
+ var containerClass = container.className;
414
+ var fragment = new DocumentFragment();
415
+ var childNodesLength = container.childNodes.length;
416
+ container.childNodes.forEach(function (node, index) {
417
+ var wrapperNode;
429
418
 
430
- if (keepEmptyNodes) {
431
- addSplitData(wrapperNode, index === 0 ? container.dataset.beforeWasSplit : true, index === childNodesLength - 1 ? container.dataset.afterWasSplit : true);
432
- }
433
- });
434
- container.replaceWith(fragment);
435
- }
436
- /**
437
- * wraps a text node into the highlight span
438
- * @param {Node} node - the node to wrap
439
- * @param {number} groupId - the highlight group
440
- * @returns {Node|null} wrapper node, if it was created
441
- */
419
+ if (index === indexToWrapNode) {
420
+ wrapperNode = wrapNode(node.cloneNode(), activeClass, currentGroupId);
421
+ } else {
422
+ wrapperNode = wrapNode(node.cloneNode(), containerClass, currentGroupId);
423
+ }
442
424
 
425
+ fragment.appendChild(wrapperNode);
443
426
 
444
- function wrapTextNode(node, groupId) {
445
- if (isWrapping && !isWrappingNode(node.parentNode) && isWrappable(node)) {
446
- $(node).wrap(getWrapper(groupId));
447
- return node.parentNode;
427
+ if (keepEmptyNodes) {
428
+ addSplitData(wrapperNode, index === 0 ? container.dataset.beforeWasSplit : true, index === childNodesLength - 1 ? container.dataset.afterWasSplit : true);
448
429
  }
430
+ });
431
+ container.replaceWith(fragment);
432
+ }
433
+ /**
434
+ * wraps a text node into the highlight span
435
+ * @param {Node} node - the node to wrap
436
+ * @param {number} groupId - the highlight group
437
+ * @returns {Node|null} wrapper node, if it was created
438
+ */
449
439
 
450
- return null;
440
+
441
+ function wrapTextNode(node, groupId) {
442
+ if (isWrapping && !isWrappingNode(node.parentNode) && isWrappable(node)) {
443
+ $(node).wrap(getWrapper(groupId));
444
+ return node.parentNode;
451
445
  }
452
- /**
453
- * We need to re-index the groups after a user highlight: either to merge groups or to resolve inconsistencies
454
- * Recursive.
455
- *
456
- * @param {Node} rootNode
457
- */
458
446
 
447
+ return null;
448
+ }
449
+ /**
450
+ * We need to re-index the groups after a user highlight: either to merge groups or to resolve inconsistencies
451
+ * Recursive.
452
+ *
453
+ * @param {Node} rootNode
454
+ */
459
455
 
460
- function reindexGroups(rootNode) {
461
- if (!rootNode) {
462
- return;
463
- }
464
456
 
465
- var childNodes = rootNode.childNodes;
466
- var i, currentNode, parent;
457
+ function reindexGroups(rootNode) {
458
+ if (!rootNode) {
459
+ return;
460
+ }
467
461
 
468
- for (i = 0; i < childNodes.length; i++) {
469
- currentNode = childNodes[i];
462
+ var childNodes = rootNode.childNodes;
463
+ var i, currentNode, parent;
470
464
 
471
- if (isWrappable(currentNode)) {
472
- parent = currentNode.parentNode;
465
+ for (i = 0; i < childNodes.length; i++) {
466
+ currentNode = childNodes[i];
473
467
 
474
- if (isWrappingNode(parent)) {
475
- if (isWrapping === false) {
476
- currentGroupId++;
477
- }
468
+ if (isWrappable(currentNode)) {
469
+ parent = currentNode.parentNode;
478
470
 
479
- isWrapping = true;
480
- parent.setAttribute(GROUP_ATTR, currentGroupId); // set the new group Id
481
- } else {
482
- isWrapping = false;
471
+ if (isWrappingNode(parent)) {
472
+ if (isWrapping === false) {
473
+ currentGroupId++;
483
474
  }
484
- } else if (isElement(currentNode)) {
485
- reindexGroups(currentNode);
475
+
476
+ isWrapping = true;
477
+ parent.setAttribute(GROUP_ATTR, currentGroupId); // set the new group Id
478
+ } else {
479
+ isWrapping = false;
486
480
  }
481
+ } else if (isElement(currentNode)) {
482
+ reindexGroups(currentNode);
487
483
  }
488
484
  }
489
- /**
490
- * Some highlights may result in having adjacent wrapping nodes. We remove them here to get a cleaner markup.
491
- *
492
- * @param {Node} rootNode
493
- */
485
+ }
486
+ /**
487
+ * Some highlights may result in having adjacent wrapping nodes. We remove them here to get a cleaner markup.
488
+ *
489
+ * @param {Node} rootNode
490
+ */
494
491
 
495
492
 
496
- function mergeAdjacentWrappingNodes(rootNode) {
497
- if (!rootNode) {
498
- return;
499
- }
493
+ function mergeAdjacentWrappingNodes(rootNode) {
494
+ if (!rootNode) {
495
+ return;
496
+ }
500
497
 
501
- var childNodes = rootNode.childNodes;
502
- var i, currentNode;
498
+ var childNodes = rootNode.childNodes;
499
+ var i, currentNode;
503
500
 
504
- for (i = 0; i < childNodes.length; i++) {
505
- currentNode = childNodes[i];
501
+ for (i = 0; i < childNodes.length; i++) {
502
+ currentNode = childNodes[i];
506
503
 
507
- if (isWrappingNode(currentNode)) {
504
+ if (isWrappingNode(currentNode)) {
505
+ if (keepEmptyNodes) {
506
+ currentNode.normalize();
507
+ }
508
+
509
+ while (isWrappingNode(currentNode.nextSibling) && currentNode.className === currentNode.nextSibling.className) {
508
510
  if (keepEmptyNodes) {
509
- currentNode.normalize();
511
+ currentNode.nextSibling.normalize();
510
512
  }
511
513
 
512
- while (isWrappingNode(currentNode.nextSibling) && currentNode.className === currentNode.nextSibling.className) {
513
- if (keepEmptyNodes) {
514
- currentNode.nextSibling.normalize();
515
- }
514
+ currentNode.firstChild.textContent += currentNode.nextSibling.firstChild.textContent;
516
515
 
517
- currentNode.firstChild.textContent += currentNode.nextSibling.firstChild.textContent;
518
-
519
- if (keepEmptyNodes) {
520
- addSplitData(currentNode, currentNode.dataset.beforeWasSplit, currentNode.nextSibling.dataset.afterWasSplit);
521
- }
522
-
523
- currentNode.parentNode.removeChild(currentNode.nextSibling);
516
+ if (keepEmptyNodes) {
517
+ addSplitData(currentNode, currentNode.dataset.beforeWasSplit, currentNode.nextSibling.dataset.afterWasSplit);
524
518
  }
525
- } else if (isElement(currentNode)) {
526
- mergeAdjacentWrappingNodes(currentNode);
519
+
520
+ currentNode.parentNode.removeChild(currentNode.nextSibling);
527
521
  }
522
+ } else if (isElement(currentNode)) {
523
+ mergeAdjacentWrappingNodes(currentNode);
528
524
  }
529
525
  }
530
- /**
531
- * Unwraps highlighted nodes with a line break or with an empty content
532
- */
526
+ }
527
+ /**
528
+ * Unwraps highlighted nodes with a line break or with an empty content
529
+ */
533
530
 
534
531
 
535
- function unWrapEmptyHighlights() {
536
- getHighlightedNodes().each((index, node) => {
537
- const nodeContent = node.textContent;
532
+ function unWrapEmptyHighlights() {
533
+ getHighlightedNodes().each(function (index, node) {
534
+ var nodeContent = node.textContent;
538
535
 
539
- if (nodeContent.trim().length === 0) {
540
- if (nodeContent.length === 0 || /\r|\n/.exec(nodeContent)) {
541
- clearSingleHighlight({
542
- target: node
543
- });
544
- }
536
+ if (nodeContent.trim().length === 0) {
537
+ if (nodeContent.length === 0 || /\r|\n/.exec(nodeContent)) {
538
+ clearSingleHighlight({
539
+ target: node
540
+ });
545
541
  }
546
- });
547
- }
548
- /**
549
- * Check condition to avoid the work of `unwrapEmptyHighlights` ahead of time, before `mergeAdjacentNodes` runs,
550
- * because in `keepEmptyNodes` case we do not want to add nodes to dom unless necessary.
551
- * Also be more strict and don't allow to select nodes with spaces only, because they may appear in unexpected places in markup
552
- * (here it's not exactly same as `unwrapEmptyHighlights`).
553
- * @param {Node} node - node which will be wrapped (highlighted)
554
- * @returns {Boolean}
555
- */
556
-
557
-
558
- function willHighlightNotBeEmptyAfterMerge(node) {
559
- if (!node.textContent.length) {
560
- return false;
561
- }
562
-
563
- if (node.textContent.trim().length) {
564
- return true;
565
542
  }
543
+ });
544
+ }
545
+ /**
546
+ * Check condition to avoid the work of `unwrapEmptyHighlights` ahead of time, before `mergeAdjacentNodes` runs,
547
+ * because in `keepEmptyNodes` case we do not want to add nodes to dom unless necessary.
548
+ * Also be more strict and don't allow to select nodes with spaces only, because they may appear in unexpected places in markup
549
+ * (here it's not exactly same as `unwrapEmptyHighlights`).
550
+ * @param {Node} node - node which will be wrapped (highlighted)
551
+ * @returns {Boolean}
552
+ */
566
553
 
567
- const prevNode = node.previousSibling;
568
- const canWrapperBeMergedWithPreviousSibling = prevNode && isWrappingNode(prevNode) && prevNode.className === className;
569
554
 
570
- if (canWrapperBeMergedWithPreviousSibling) {
571
- return true;
572
- }
555
+ function willHighlightNotBeEmptyAfterMerge(node) {
556
+ if (!node.textContent.length) {
557
+ return false;
558
+ }
573
559
 
574
- const nextNode = node.nextSibling;
575
- const canWrapperBeMergedWithNextSibling = nextNode && isWrappingNode(nextNode) && nextNode.className === className;
560
+ if (node.textContent.trim().length) {
561
+ return true;
562
+ }
576
563
 
577
- if (canWrapperBeMergedWithNextSibling) {
578
- return true;
579
- }
564
+ var prevNode = node.previousSibling;
565
+ var canWrapperBeMergedWithPreviousSibling = prevNode && isWrappingNode(prevNode) && prevNode.className === className;
580
566
 
581
- return false;
567
+ if (canWrapperBeMergedWithPreviousSibling) {
568
+ return true;
582
569
  }
583
- /**
584
- * `range.surroundContents` can create empty text nodes,
585
- * which will cause trouble in `mergeAdjacentNodes` later (in `keepEmptyNodes` case).
586
- * This method surrounds range, then removes those nodes
587
- * @param {Range} range
588
- * @param {Node} wrapperNode
589
- */
590
570
 
571
+ var nextNode = node.nextSibling;
572
+ var canWrapperBeMergedWithNextSibling = nextNode && isWrappingNode(nextNode) && nextNode.className === className;
591
573
 
592
- function rangeSurroundContentsNoEmptyNodes(range, wrapperNode) {
593
- const containerPreviousSibling = range.commonAncestorContainer.previousSibling;
594
- const containerNextSibling = range.commonAncestorContainer.nextSibling;
595
- range.surroundContents(wrapperNode);
596
- removeEmptyTextNodeIfDifferent(wrapperNode.previousSibling, containerPreviousSibling);
597
- removeEmptyTextNodeIfDifferent(wrapperNode.nextSibling, containerNextSibling);
574
+ if (canWrapperBeMergedWithNextSibling) {
575
+ return true;
598
576
  }
599
- /**
600
- * Remove `node`, if it's an empty text node and is *not* the same node as `nodeToCompare`
601
- * @param {Node} node
602
- * @param {Node} nodeToCompare
603
- */
604
577
 
578
+ return false;
579
+ }
580
+ /**
581
+ * `range.surroundContents` can create empty text nodes,
582
+ * which will cause trouble in `mergeAdjacentNodes` later (in `keepEmptyNodes` case).
583
+ * This method surrounds range, then removes those nodes
584
+ * @param {Range} range
585
+ * @param {Node} wrapperNode
586
+ */
605
587
 
606
- function removeEmptyTextNodeIfDifferent(node, nodeToCompare) {
607
- if (node && node !== nodeToCompare && isText(node) && node.textContent.length === 0) {
608
- node.remove();
609
- }
610
- }
611
- /**
612
- * Remove all wrapping nodes from markup
613
- */
614
588
 
589
+ function rangeSurroundContentsNoEmptyNodes(range, wrapperNode) {
590
+ var containerPreviousSibling = range.commonAncestorContainer.previousSibling;
591
+ var containerNextSibling = range.commonAncestorContainer.nextSibling;
592
+ range.surroundContents(wrapperNode);
593
+ removeEmptyTextNodeIfDifferent(wrapperNode.previousSibling, containerPreviousSibling);
594
+ removeEmptyTextNodeIfDifferent(wrapperNode.nextSibling, containerNextSibling);
595
+ }
596
+ /**
597
+ * Remove `node`, if it's an empty text node and is *not* the same node as `nodeToCompare`
598
+ * @param {Node} node
599
+ * @param {Node} nodeToCompare
600
+ */
615
601
 
616
- function clearHighlights() {
617
- getHighlightedNodes().each(function (i, elem) {
618
- if (!keepEmptyNodes) {
619
- var $wrapped = $(this);
620
- $wrapped.replaceWith($wrapped.text());
621
- } else {
622
- clearSingleHighlight({
623
- target: elem
624
- });
625
- }
626
- });
602
+
603
+ function removeEmptyTextNodeIfDifferent(node, nodeToCompare) {
604
+ if (node && node !== nodeToCompare && isText(node) && node.textContent.length === 0) {
605
+ node.remove();
627
606
  }
628
- /**
629
- * Remove unwrap dom node
630
- */
607
+ }
608
+ /**
609
+ * Remove all wrapping nodes from markup
610
+ */
631
611
 
632
612
 
633
- function clearSingleHighlight(e) {
613
+ function clearHighlights() {
614
+ getHighlightedNodes().each(function (i, elem) {
634
615
  if (!keepEmptyNodes) {
635
- const $wrapped = $(e.target);
636
- const text = $wrapped.text(); // NOTE: JQuery replaceWith is not working with empty string https://bugs.jquery.com/ticket/13401
616
+ var $wrapped = $(this);
617
+ $wrapped.replaceWith($wrapped.text());
618
+ } else {
619
+ clearSingleHighlight({
620
+ target: elem
621
+ });
622
+ }
623
+ });
624
+ }
625
+ /**
626
+ * Remove unwrap dom node
627
+ */
637
628
 
638
- if (text === '') {
639
- $wrapped.remove();
640
- } else {
641
- $wrapped.replaceWith(text);
642
- }
629
+
630
+ function clearSingleHighlight(e) {
631
+ if (!keepEmptyNodes) {
632
+ var $wrapped = $(e.target);
633
+ var text = $wrapped.text(); // NOTE: JQuery replaceWith is not working with empty string https://bugs.jquery.com/ticket/13401
634
+
635
+ if (text === '') {
636
+ $wrapped.remove();
643
637
  } else {
644
- const nodeToRemove = e.target;
645
- const nodeToRemoveText = nodeToRemove.textContent;
646
- const beforeWasSplit = nodeToRemove.dataset.beforeWasSplit === 'true';
647
- const afterWasSplit = nodeToRemove.dataset.afterWasSplit === 'true';
648
- const prevNode = nodeToRemove.previousSibling;
649
- const nextNode = nodeToRemove.nextSibling;
650
-
651
- if (beforeWasSplit && prevNode && isText(prevNode) && prevNode.textContent) {
652
- //append text to previous sibling
653
- prevNode.textContent += nodeToRemoveText;
654
- nodeToRemove.remove();
655
-
656
- if (afterWasSplit && prevNode.nextSibling && isText(prevNode.nextSibling) && prevNode.nextSibling.textContent) {
657
- //merge it with next sibling
658
- prevNode.textContent += prevNode.nextSibling.textContent;
659
- prevNode.nextSibling.remove();
660
- }
661
- } else if (afterWasSplit && nextNode && isText(nextNode) && nextNode.textContent) {
662
- //append text to next sibling
663
- nextNode.textContent = nodeToRemoveText + nextNode.textContent;
664
- nodeToRemove.remove();
665
- } else if (nodeToRemoveText) {
666
- //keep text in a separate text node
667
- nodeToRemove.replaceWith(document.createTextNode(nodeToRemoveText));
668
- } else {
669
- //text is empty, just remove it
670
- nodeToRemove.remove();
638
+ $wrapped.replaceWith(text);
639
+ }
640
+ } else {
641
+ var nodeToRemove = e.target;
642
+ var nodeToRemoveText = nodeToRemove.textContent;
643
+ var beforeWasSplit = nodeToRemove.dataset.beforeWasSplit === 'true';
644
+ var afterWasSplit = nodeToRemove.dataset.afterWasSplit === 'true';
645
+ var prevNode = nodeToRemove.previousSibling;
646
+ var nextNode = nodeToRemove.nextSibling;
647
+
648
+ if (beforeWasSplit && prevNode && isText(prevNode) && prevNode.textContent) {
649
+ //append text to previous sibling
650
+ prevNode.textContent += nodeToRemoveText;
651
+ nodeToRemove.remove();
652
+
653
+ if (afterWasSplit && prevNode.nextSibling && isText(prevNode.nextSibling) && prevNode.nextSibling.textContent) {
654
+ //merge it with next sibling
655
+ prevNode.textContent += prevNode.nextSibling.textContent;
656
+ prevNode.nextSibling.remove();
671
657
  }
658
+ } else if (afterWasSplit && nextNode && isText(nextNode) && nextNode.textContent) {
659
+ //append text to next sibling
660
+ nextNode.textContent = nodeToRemoveText + nextNode.textContent;
661
+ nodeToRemove.remove();
662
+ } else if (nodeToRemoveText) {
663
+ //keep text in a separate text node
664
+ nodeToRemove.replaceWith(document.createTextNode(nodeToRemoveText));
665
+ } else {
666
+ //text is empty, just remove it
667
+ nodeToRemove.remove();
672
668
  }
673
669
  }
674
- /**
675
- * Index-related functions:
676
- * ========================
677
- * To allow saving and restoring highlights on an equivalent, but different, DOM tree (for example if the markup is deleted and re-created)
678
- * we build an index containing the status of each text node:
679
- * - not highlighted
680
- * - fully highlighted
681
- * - partially highlighted (= with inline ranges)
682
- *
683
- * This index will be used to restore a selection on the new DOM tree
684
- */
670
+ }
671
+ /**
672
+ * Index-related functions:
673
+ * ========================
674
+ * To allow saving and restoring highlights on an equivalent, but different, DOM tree (for example if the markup is deleted and re-created)
675
+ * we build an index containing the status of each text node:
676
+ * - not highlighted
677
+ * - fully highlighted
678
+ * - partially highlighted (= with inline ranges)
679
+ *
680
+ * This index will be used to restore a selection on the new DOM tree
681
+ */
685
682
 
686
- /**
687
- * Bootstrap the process of building the highlight index
688
- * @returns {Object[]|BuildModelResultKeepEmpty|null}
689
- */
683
+ /**
684
+ * Bootstrap the process of building the highlight index
685
+ * @returns {Object[]|BuildModelResultKeepEmpty|null}
686
+ */
690
687
 
691
688
 
692
- function getHighlightIndex() {
693
- var rootNode = getContainer();
689
+ function getHighlightIndex() {
690
+ var rootNode = getContainer();
694
691
 
695
- if (!keepEmptyNodes) {
696
- var highlightIndex = [];
692
+ if (!keepEmptyNodes) {
693
+ var highlightIndex = [];
697
694
 
698
- if (rootNode) {
699
- rootNode.normalize();
700
- textNodesIndex = 0;
701
- buildHighlightIndex(rootNode, highlightIndex);
702
- }
695
+ if (rootNode) {
696
+ rootNode.normalize();
697
+ textNodesIndex = 0;
698
+ buildHighlightIndex(rootNode, highlightIndex);
699
+ }
703
700
 
704
- return highlightIndex;
701
+ return highlightIndex;
702
+ } else {
703
+ if (rootNode) {
704
+ return buildHighlightModelKeepEmpty(rootNode);
705
705
  } else {
706
- if (rootNode) {
707
- return buildHighlightModelKeepEmpty(rootNode);
708
- } else {
709
- return null;
710
- }
706
+ return null;
711
707
  }
712
708
  }
713
- /**
714
- * Traverse the DOM tree to create the text Nodes index. Recursive.
715
- * @param {Node} rootNode
716
- * @param {Object[]} highlightIndex
717
- */
718
-
719
-
720
- function buildHighlightIndex(rootNode, highlightIndex) {
721
- var childNodes = rootNode.childNodes;
722
- var i, currentNode;
723
- var nodeInfos, inlineRange, inlineOffset, nodesToSkip;
709
+ }
710
+ /**
711
+ * Traverse the DOM tree to create the text Nodes index. Recursive.
712
+ * @param {Node} rootNode
713
+ * @param {Object[]} highlightIndex
714
+ */
724
715
 
725
- for (i = 0; i < childNodes.length; i++) {
726
- currentNode = childNodes[i]; // Skip blacklisted nodes
727
716
 
728
- if (isBlacklisted(currentNode)) {
729
- continue;
730
- } // A simple node not highlighted and isolated (= not followed by an wrapped text)
731
- else if (isWrappable(currentNode) && !isWrappingNode(currentNode.nextSibling)) {
732
- highlightIndex[textNodesIndex] = {
733
- highlighted: false
734
- };
735
- textNodesIndex++; // an isolated node (= not followed by a highlight table text) with its whole content highlighted
736
- } else if (isWrappingNode(currentNode) && !isText(currentNode.nextSibling) && (!isWrappingNode(currentNode.nextSibling) || currentNode.className === currentNode.nextSibling.className)) {
737
- highlightIndex[textNodesIndex] = {
738
- highlighted: true,
739
- groupId: currentNode.getAttribute(GROUP_ATTR),
740
- c: getColorByClassName(currentNode.className)
741
- };
742
- textNodesIndex++; // less straightforward: a succession of (at least) 1 wrapping node with 1 wrappable text node, in either order, and possibly more
743
- // the trick is to create a unique text node on which we will be able to re-apply multiple partial highlights
744
- // for this, we use 'inlineRanges'
745
- } else if (isHotNode(currentNode)) {
746
- nodeInfos = {
747
- highlighted: true,
748
- inlineRanges: []
749
- };
750
- nodesToSkip = -1;
751
- inlineOffset = 0;
752
-
753
- while (currentNode) {
754
- if (isWrappingNode(currentNode)) {
755
- inlineRange = {
756
- groupId: currentNode.getAttribute(GROUP_ATTR),
757
- c: getColorByClassName(currentNode.className)
758
- };
759
-
760
- if (isText(currentNode.previousSibling) || isWrappingNode(currentNode.previousSibling)) {
761
- inlineRange.startOffset = inlineOffset;
762
- }
717
+ function buildHighlightIndex(rootNode, highlightIndex) {
718
+ var childNodes = rootNode.childNodes;
719
+ var i, currentNode;
720
+ var nodeInfos, inlineRange, inlineOffset, nodesToSkip;
721
+
722
+ for (i = 0; i < childNodes.length; i++) {
723
+ currentNode = childNodes[i]; // Skip blacklisted nodes
724
+
725
+ if (isBlacklisted(currentNode)) {
726
+ continue;
727
+ } // A simple node not highlighted and isolated (= not followed by an wrapped text)
728
+ else if (isWrappable(currentNode) && !isWrappingNode(currentNode.nextSibling)) {
729
+ highlightIndex[textNodesIndex] = {
730
+ highlighted: false
731
+ };
732
+ textNodesIndex++; // an isolated node (= not followed by a highlight table text) with its whole content highlighted
733
+ } else if (isWrappingNode(currentNode) && !isText(currentNode.nextSibling) && (!isWrappingNode(currentNode.nextSibling) || currentNode.className === currentNode.nextSibling.className)) {
734
+ highlightIndex[textNodesIndex] = {
735
+ highlighted: true,
736
+ groupId: currentNode.getAttribute(GROUP_ATTR),
737
+ c: getColorByClassName(currentNode.className)
738
+ };
739
+ textNodesIndex++; // less straightforward: a succession of (at least) 1 wrapping node with 1 wrappable text node, in either order, and possibly more
740
+ // the trick is to create a unique text node on which we will be able to re-apply multiple partial highlights
741
+ // for this, we use 'inlineRanges'
742
+ } else if (isHotNode(currentNode)) {
743
+ nodeInfos = {
744
+ highlighted: true,
745
+ inlineRanges: []
746
+ };
747
+ nodesToSkip = -1;
748
+ inlineOffset = 0;
749
+
750
+ while (currentNode) {
751
+ if (isWrappingNode(currentNode)) {
752
+ inlineRange = {
753
+ groupId: currentNode.getAttribute(GROUP_ATTR),
754
+ c: getColorByClassName(currentNode.className)
755
+ };
763
756
 
764
- if (isText(currentNode.nextSibling) || isWrappingNode(currentNode.nextSibling)) {
765
- inlineRange.endOffset = inlineOffset + currentNode.textContent.length;
766
- }
757
+ if (isText(currentNode.previousSibling) || isWrappingNode(currentNode.previousSibling)) {
758
+ inlineRange.startOffset = inlineOffset;
759
+ }
767
760
 
768
- nodeInfos.inlineRanges.push(inlineRange);
761
+ if (isText(currentNode.nextSibling) || isWrappingNode(currentNode.nextSibling)) {
762
+ inlineRange.endOffset = inlineOffset + currentNode.textContent.length;
769
763
  }
770
764
 
771
- inlineOffset += currentNode.textContent.length;
772
- currentNode = isHotNode(currentNode.nextSibling) || isText(currentNode.nextSibling) ? currentNode.nextSibling : null;
773
- nodesToSkip++;
765
+ nodeInfos.inlineRanges.push(inlineRange);
774
766
  }
775
767
 
776
- i += nodesToSkip; // we increase the loop counter to avoid looping over the nodes that we just analyzed
777
-
778
- highlightIndex[textNodesIndex] = nodeInfos;
779
- textNodesIndex++; // go deeper in the node tree...
780
- } else if (isElement(currentNode)) {
781
- buildHighlightIndex(currentNode, highlightIndex);
768
+ inlineOffset += currentNode.textContent.length;
769
+ currentNode = isHotNode(currentNode.nextSibling) || isText(currentNode.nextSibling) ? currentNode.nextSibling : null;
770
+ nodesToSkip++;
782
771
  }
772
+
773
+ i += nodesToSkip; // we increase the loop counter to avoid looping over the nodes that we just analyzed
774
+
775
+ highlightIndex[textNodesIndex] = nodeInfos;
776
+ textNodesIndex++; // go deeper in the node tree...
777
+ } else if (isElement(currentNode)) {
778
+ buildHighlightIndex(currentNode, highlightIndex);
783
779
  }
784
780
  }
785
- /**
786
- * @typedef HighlightEntryKeepEmpty
787
- * @property {String} groupId
788
- * @property {String} c - color
789
- * @property {Number} offsetBefore
790
- * @property {Number} textLength
791
- * @property {String} beforeWasSplit
792
- * @property {String} afterWasSplit
793
- * @property {Array<Number>} path - on each level from root container to highlight, index among siblings
794
- */
781
+ }
782
+ /**
783
+ * @typedef HighlightEntryKeepEmpty
784
+ * @property {String} groupId
785
+ * @property {String} c - color
786
+ * @property {Number} offsetBefore
787
+ * @property {Number} textLength
788
+ * @property {String} beforeWasSplit
789
+ * @property {String} afterWasSplit
790
+ * @property {Array<Number>} path - on each level from root container to highlight, index among siblings
791
+ */
795
792
 
796
- /**
797
- * @typedef BuildModelResultKeepEmpty
798
- * @property {HighlightEntryKeepEmpty[]} highlightModel
799
- * @property {NodeList} wrapperNodes
800
- */
793
+ /**
794
+ * @typedef BuildModelResultKeepEmpty
795
+ * @property {HighlightEntryKeepEmpty[]} highlightModel
796
+ * @property {NodeList} wrapperNodes
797
+ */
801
798
 
802
- /**
803
- * For `keepEmptyNodes` option, creates data model of highlights.
804
- * Additionally returns array of highlight nodes. Traverses DOM tree.
805
- * @param {Node} rootNode
806
- * @returns {BuildModelResultKeepEmpty|null} result
807
- */
799
+ /**
800
+ * For `keepEmptyNodes` option, creates data model of highlights.
801
+ * Additionally returns array of highlight nodes. Traverses DOM tree.
802
+ * @param {Node} rootNode
803
+ * @returns {BuildModelResultKeepEmpty|null} result
804
+ */
808
805
 
809
806
 
810
- function buildHighlightModelKeepEmpty(rootNode) {
811
- const classNames = options.colors ? Object.values(options.colors) : [className];
812
- const wrapperNodesSelector = classNames.map(cls => containerSelector + ' .' + cls).join(', ');
813
- const wrapperNodes = Array.from(document.querySelectorAll(wrapperNodesSelector)).filter(node => !isBlacklisted(node));
807
+ function buildHighlightModelKeepEmpty(rootNode) {
808
+ var classNames = options.colors ? Object.values(options.colors) : [className];
809
+ var wrapperNodesSelector = classNames.map(function (cls) {
810
+ return containerSelector + ' .' + cls;
811
+ }).join(', ');
812
+ var wrapperNodes = Array.from(document.querySelectorAll(wrapperNodesSelector)).filter(function (node) {
813
+ return !isBlacklisted(node);
814
+ });
814
815
 
815
- if (!wrapperNodes.length) {
816
- return null;
817
- }
816
+ if (!wrapperNodes.length) {
817
+ return null;
818
+ }
818
819
 
819
- var highlightModel = [];
820
- const indexCache = new Map();
820
+ var highlightModel = [];
821
+ var indexCache = new Map();
821
822
 
822
- for (var k = 0; k < wrapperNodes.length; k++) {
823
- var wrapperNode = wrapperNodes[k]; //get info about highlight itself
823
+ for (var k = 0; k < wrapperNodes.length; k++) {
824
+ var wrapperNode = wrapperNodes[k]; //get info about highlight itself
824
825
 
825
- var offsetBefore = 0;
826
- var prevNode = wrapperNode.previousSibling;
826
+ var offsetBefore = 0;
827
+ var prevNode = wrapperNode.previousSibling;
827
828
 
828
- if (prevNode && isText(prevNode)) {
829
- const beforeWasSplit = wrapperNode.dataset.beforeWasSplit === 'true';
829
+ if (prevNode && isText(prevNode)) {
830
+ var beforeWasSplit = wrapperNode.dataset.beforeWasSplit === 'true';
830
831
 
831
- if (beforeWasSplit) {
832
- offsetBefore = prevNode.textContent.length;
833
- }
832
+ if (beforeWasSplit) {
833
+ offsetBefore = prevNode.textContent.length;
834
834
  }
835
+ }
835
836
 
836
- var highlightData = {
837
- groupId: wrapperNode.getAttribute(GROUP_ATTR),
838
- c: getColorByClassName(wrapperNode.className),
839
- offsetBefore,
840
- textLength: wrapperNode.textContent.length,
841
- beforeWasSplit: wrapperNode.dataset.beforeWasSplit,
842
- afterWasSplit: wrapperNode.dataset.afterWasSplit,
843
- path: []
844
- }; //get info about its position in the tree: path through all parents from rootNode to highlight
837
+ var highlightData = {
838
+ groupId: wrapperNode.getAttribute(GROUP_ATTR),
839
+ c: getColorByClassName(wrapperNode.className),
840
+ offsetBefore: offsetBefore,
841
+ textLength: wrapperNode.textContent.length,
842
+ beforeWasSplit: wrapperNode.dataset.beforeWasSplit,
843
+ afterWasSplit: wrapperNode.dataset.afterWasSplit,
844
+ path: []
845
+ }; //get info about its position in the tree: path through all parents from rootNode to highlight
846
+
847
+ var currentNode = wrapperNode;
848
+
849
+ while (currentNode && currentNode !== rootNode) {
850
+ var indexInModel = indexCache.get(currentNode);
851
+
852
+ if (!indexInModel && indexInModel !== 0) {
853
+ //should be more reliable to ignore empty nodes when indexing
854
+ var childNodes = Array.from(currentNode.parentNode.childNodes).filter(function (node) {
855
+ return !(isText(node) && !node.textContent.length);
856
+ }); //index among its non-empty siblings
857
+
858
+ indexInModel = childNodes.indexOf(currentNode);
859
+ indexCache.set(currentNode, indexInModel);
860
+ }
845
861
 
846
- let currentNode = wrapperNode;
862
+ highlightData.path.unshift(indexInModel);
863
+ currentNode = currentNode.parentNode;
864
+ } //add info about highlight and its position to model
847
865
 
848
- while (currentNode && currentNode !== rootNode) {
849
- let indexInModel = indexCache.get(currentNode);
850
866
 
851
- if (!indexInModel && indexInModel !== 0) {
852
- //should be more reliable to ignore empty nodes when indexing
853
- const childNodes = Array.from(currentNode.parentNode.childNodes).filter(node => !(isText(node) && !node.textContent.length)); //index among its non-empty siblings
867
+ highlightModel.push(highlightData);
868
+ }
854
869
 
855
- indexInModel = childNodes.indexOf(currentNode);
856
- indexCache.set(currentNode, indexInModel);
857
- }
870
+ return {
871
+ highlightModel: highlightModel,
872
+ wrapperNodes: wrapperNodes
873
+ };
874
+ }
875
+ /**
876
+ * Bootstrap the process of restoring the highlights from an index
877
+ * @param {Object[]|HighlightEntryKeepEmpty[]|null} highlightIndex
878
+ */
858
879
 
859
- highlightData.path.unshift(indexInModel);
860
- currentNode = currentNode.parentNode;
861
- } //add info about highlight and its position to model
862
880
 
881
+ function highlightFromIndex(highlightIndex) {
882
+ var rootNode = getContainer();
863
883
 
864
- highlightModel.push(highlightData);
884
+ if (rootNode) {
885
+ if (!keepEmptyNodes) {
886
+ rootNode.normalize();
887
+ textNodesIndex = 0;
888
+ restoreHighlight(rootNode, highlightIndex);
889
+ } else {
890
+ restoreHighlightKeepEmpty(rootNode, highlightIndex);
865
891
  }
866
-
867
- return {
868
- highlightModel,
869
- wrapperNodes
870
- };
871
892
  }
872
- /**
873
- * Bootstrap the process of restoring the highlights from an index
874
- * @param {Object[]|HighlightEntryKeepEmpty[]|null} highlightIndex
875
- */
893
+ }
894
+ /**
895
+ * Traverse the DOM tree to wraps the text nodes according to the highlight index. Recursive.
896
+ * @param {Node} rootNode
897
+ * @param {Object[]} highlightIndex
898
+ */
876
899
 
877
900
 
878
- function highlightFromIndex(highlightIndex) {
879
- var rootNode = getContainer();
901
+ function restoreHighlight(rootNode, highlightIndex) {
902
+ var childNodes = rootNode.childNodes;
903
+ var i, currentNode, parent;
904
+ var nodeInfos, nodesToSkip, range, initialChildCount;
880
905
 
881
- if (rootNode) {
882
- if (!keepEmptyNodes) {
883
- rootNode.normalize();
884
- textNodesIndex = 0;
885
- restoreHighlight(rootNode, highlightIndex);
886
- } else {
887
- restoreHighlightKeepEmpty(rootNode, highlightIndex);
888
- }
889
- }
890
- }
891
- /**
892
- * Traverse the DOM tree to wraps the text nodes according to the highlight index. Recursive.
893
- * @param {Node} rootNode
894
- * @param {Object[]} highlightIndex
895
- */
906
+ for (i = 0; i < childNodes.length; i++) {
907
+ currentNode = childNodes[i];
896
908
 
909
+ if (isBlacklisted(currentNode)) {
910
+ continue;
911
+ } else if (isWrappable(currentNode)) {
912
+ parent = currentNode.parentNode;
913
+ initialChildCount = parent.childNodes.length;
914
+ nodeInfos = highlightIndex[textNodesIndex];
897
915
 
898
- function restoreHighlight(rootNode, highlightIndex) {
899
- var childNodes = rootNode.childNodes;
900
- var i, currentNode, parent;
901
- var nodeInfos, nodesToSkip, range, initialChildCount;
902
-
903
- for (i = 0; i < childNodes.length; i++) {
904
- currentNode = childNodes[i];
905
-
906
- if (isBlacklisted(currentNode)) {
907
- continue;
908
- } else if (isWrappable(currentNode)) {
909
- parent = currentNode.parentNode;
910
- initialChildCount = parent.childNodes.length;
911
- nodeInfos = highlightIndex[textNodesIndex];
912
-
913
- if (nodeInfos.highlighted === true) {
914
- if (_.isArray(nodeInfos.inlineRanges)) {
915
- nodeInfos.inlineRanges.reverse();
916
- nodeInfos.inlineRanges.forEach(function (inlineRange) {
917
- range = document.createRange();
918
- range.setStart(currentNode, inlineRange.startOffset || 0);
919
- range.setEnd(currentNode, inlineRange.endOffset || currentNode.textContent.length);
920
- range.surroundContents(getWrapper(inlineRange.groupId, getClassNameByColor(inlineRange.c)));
921
- }); // fully highlighted text node
922
- } else {
916
+ if (nodeInfos.highlighted === true) {
917
+ if (_.isArray(nodeInfos.inlineRanges)) {
918
+ nodeInfos.inlineRanges.reverse();
919
+ nodeInfos.inlineRanges.forEach(function (inlineRange) {
923
920
  range = document.createRange();
924
- range.selectNodeContents(currentNode);
925
- range.surroundContents(getWrapper(nodeInfos.groupId, getClassNameByColor(nodeInfos.c)));
926
- } // we do want to loop over the nodes created by the wrapping operation
927
-
921
+ range.setStart(currentNode, inlineRange.startOffset || 0);
922
+ range.setEnd(currentNode, inlineRange.endOffset || currentNode.textContent.length);
923
+ range.surroundContents(getWrapper(inlineRange.groupId, getClassNameByColor(inlineRange.c)));
924
+ }); // fully highlighted text node
925
+ } else {
926
+ range = document.createRange();
927
+ range.selectNodeContents(currentNode);
928
+ range.surroundContents(getWrapper(nodeInfos.groupId, getClassNameByColor(nodeInfos.c)));
929
+ } // we do want to loop over the nodes created by the wrapping operation
928
930
 
929
- nodesToSkip = parent.childNodes.length - initialChildCount;
930
- i += nodesToSkip;
931
- }
932
931
 
933
- textNodesIndex++;
934
- } else if (isElement(currentNode)) {
935
- restoreHighlight(currentNode, highlightIndex);
932
+ nodesToSkip = parent.childNodes.length - initialChildCount;
933
+ i += nodesToSkip;
936
934
  }
935
+
936
+ textNodesIndex++;
937
+ } else if (isElement(currentNode)) {
938
+ restoreHighlight(currentNode, highlightIndex);
937
939
  }
938
940
  }
939
- /**
940
- * For `keepEmptyNodes` option, wraps the text nodes according to highlights data model.
941
- * Traverses and updates DOM tree. Shouldn't throw errors in case of mismatches.
942
- * @param {Node} rootNode
943
- * @param {HighlightEntryKeepEmpty[]|null} highlightModel
944
- */
945
-
941
+ }
942
+ /**
943
+ * For `keepEmptyNodes` option, wraps the text nodes according to highlights data model.
944
+ * Traverses and updates DOM tree. Shouldn't throw errors in case of mismatches.
945
+ * @param {Node} rootNode
946
+ * @param {HighlightEntryKeepEmpty[]|null} highlightModel
947
+ */
946
948
 
947
- function restoreHighlightKeepEmpty(rootNode, highlightModel) {
948
- if (!highlightModel) {
949
- return;
950
- }
951
949
 
952
- var currentModel;
953
- var range;
950
+ function restoreHighlightKeepEmpty(rootNode, highlightModel) {
951
+ if (!highlightModel) {
952
+ return;
953
+ }
954
954
 
955
- for (var k = 0; k < highlightModel.length; k++) {
956
- currentModel = highlightModel[k]; //find node to wrap - go through nodes until we reach level where node to wrap will be
955
+ var currentModel;
956
+ var range;
957
957
 
958
- let childNodes;
959
- let indexInModel;
960
- let currentParentNode = rootNode;
961
- let pathNotFound = false;
958
+ for (var k = 0; k < highlightModel.length; k++) {
959
+ currentModel = highlightModel[k]; //find node to wrap - go through nodes until we reach level where node to wrap will be
962
960
 
963
- if (!currentModel.path || !currentModel.path.length) {
964
- continue; //something went wrong
965
- }
961
+ var childNodes = void 0;
962
+ var indexInModel = void 0;
963
+ var currentParentNode = rootNode;
964
+ var pathNotFound = false;
966
965
 
967
- for (var m = 0; m < currentModel.path.length; m++) {
968
- //path was counted among non-empty nodes
969
- childNodes = Array.from(currentParentNode.childNodes).filter(node => !(isText(node) && !node.textContent.length));
970
- indexInModel = currentModel.path[m];
971
- currentParentNode = childNodes[indexInModel];
966
+ if (!currentModel.path || !currentModel.path.length) {
967
+ continue; //something went wrong
968
+ }
972
969
 
973
- if (!currentParentNode && m < currentModel.path.length - 1) {
974
- //node on last level may not exist yet, no need to fail. See `nodeAtIndex`
975
- pathNotFound = true;
976
- break;
977
- }
970
+ for (var m = 0; m < currentModel.path.length; m++) {
971
+ //path was counted among non-empty nodes
972
+ childNodes = Array.from(currentParentNode.childNodes).filter(function (node) {
973
+ return !(isText(node) && !node.textContent.length);
974
+ });
975
+ indexInModel = currentModel.path[m];
976
+ currentParentNode = childNodes[indexInModel];
977
+
978
+ if (!currentParentNode && m < currentModel.path.length - 1) {
979
+ //node on last level may not exist yet, no need to fail. See `nodeAtIndex`
980
+ pathNotFound = true;
981
+ break;
978
982
  }
983
+ }
979
984
 
980
- if (pathNotFound) {
981
- continue; //something went wrong
982
- } //add single highlight
985
+ if (pathNotFound) {
986
+ continue; //something went wrong
987
+ } //add single highlight
983
988
 
984
989
 
985
- var nodeAtIndex = null;
990
+ var nodeAtIndex = null;
986
991
 
987
- if (!currentModel.offsetBefore) {
988
- //wrap starts on this node
989
- nodeAtIndex = childNodes[indexInModel];
992
+ if (!currentModel.offsetBefore) {
993
+ //wrap starts on this node
994
+ nodeAtIndex = childNodes[indexInModel];
990
995
 
991
- if (!nodeAtIndex || !isText(nodeAtIndex) || isBlacklisted(nodeAtIndex)) {
992
- continue; //something went wrong
993
- }
994
- } else {
995
- //split previousSibling to create a node for wrapping
996
- var nodeBefore = childNodes[indexInModel - 1];
996
+ if (!nodeAtIndex || !isText(nodeAtIndex) || isBlacklisted(nodeAtIndex)) {
997
+ continue; //something went wrong
998
+ }
999
+ } else {
1000
+ //split previousSibling to create a node for wrapping
1001
+ var nodeBefore = childNodes[indexInModel - 1];
997
1002
 
998
- if (!nodeBefore || !isText(nodeBefore) || nodeBefore.textContent.length <= currentModel.offsetBefore || isBlacklisted(nodeBefore)) {
999
- continue; //something went wrong
1000
- }
1003
+ if (!nodeBefore || !isText(nodeBefore) || nodeBefore.textContent.length <= currentModel.offsetBefore || isBlacklisted(nodeBefore)) {
1004
+ continue; //something went wrong
1005
+ }
1001
1006
 
1002
- nodeAtIndex = nodeBefore.splitText(currentModel.offsetBefore);
1003
- } //cut off its end
1007
+ nodeAtIndex = nodeBefore.splitText(currentModel.offsetBefore);
1008
+ } //cut off its end
1004
1009
 
1005
1010
 
1006
- if (nodeAtIndex.textContent.length > currentModel.textLength) {
1007
- nodeAtIndex.splitText(currentModel.textLength);
1008
- } //wrap
1011
+ if (nodeAtIndex.textContent.length > currentModel.textLength) {
1012
+ nodeAtIndex.splitText(currentModel.textLength);
1013
+ } //wrap
1009
1014
 
1010
1015
 
1011
- const wrapperNode = getWrapper(currentModel.groupId, getClassNameByColor(currentModel.c));
1012
- addSplitData(wrapperNode, currentModel.beforeWasSplit, currentModel.afterWasSplit);
1013
- range = document.createRange();
1014
- range.selectNodeContents(nodeAtIndex);
1015
- rangeSurroundContentsNoEmptyNodes(range, wrapperNode);
1016
- }
1016
+ var wrapperNode = getWrapper(currentModel.groupId, getClassNameByColor(currentModel.c));
1017
+ addSplitData(wrapperNode, currentModel.beforeWasSplit, currentModel.afterWasSplit);
1018
+ range = document.createRange();
1019
+ range.selectNodeContents(nodeAtIndex);
1020
+ rangeSurroundContentsNoEmptyNodes(range, wrapperNode);
1017
1021
  }
1018
- /**
1019
- * Set highlighter color
1020
- * @param {string} color Active highlighter color
1021
- */
1022
+ }
1023
+ /**
1024
+ * Set highlighter color
1025
+ * @param {string} color Active highlighter color
1026
+ */
1022
1027
 
1023
1028
 
1024
- const setActiveColor = color => {
1025
- if (options.colors[color]) {
1026
- className = options.colors[color];
1027
- }
1028
- };
1029
- /**
1030
- * Helpers
1031
- */
1029
+ var setActiveColor = function setActiveColor(color) {
1030
+ if (options.colors[color]) {
1031
+ className = options.colors[color];
1032
+ }
1033
+ };
1034
+ /**
1035
+ * Helpers
1036
+ */
1032
1037
 
1033
- /**
1034
- * Return the object key contains the given value
1035
- * @param {Object} object
1036
- * @param {any} value
1037
- * @return {string|undefined}
1038
- */
1038
+ /**
1039
+ * Return the object key contains the given value
1040
+ * @param {Object} object
1041
+ * @param {any} value
1042
+ * @return {string|undefined}
1043
+ */
1039
1044
 
1040
1045
 
1041
- const getKeyByValue = (object, value) => Object.keys(object).find(key => object[key] === value);
1042
- /**
1043
- * Returns color identifier for the given class name
1044
- * @param {string} highlighterClassName Class name of highlighter classes
1045
- * @returns {string|number} Color identifier
1046
- */
1046
+ var getKeyByValue = function getKeyByValue(object, value) {
1047
+ return Object.keys(object).find(function (key) {
1048
+ return object[key] === value;
1049
+ });
1050
+ };
1051
+ /**
1052
+ * Returns color identifier for the given class name
1053
+ * @param {string} highlighterClassName Class name of highlighter classes
1054
+ * @returns {string|number} Color identifier
1055
+ */
1047
1056
 
1048
1057
 
1049
- const getColorByClassName = highlighterClassName => {
1050
- if (options.colors) {
1051
- return getKeyByValue(options.colors, highlighterClassName);
1052
- }
1058
+ var getColorByClassName = function getColorByClassName(highlighterClassName) {
1059
+ if (options.colors) {
1060
+ return getKeyByValue(options.colors, highlighterClassName);
1061
+ }
1053
1062
 
1054
- return className;
1055
- };
1056
- /**
1057
- * Returns class name for the given color identifier
1058
- * @param {string|number} color Color identifier
1059
- * @returns {string} Class name
1060
- */
1063
+ return className;
1064
+ };
1065
+ /**
1066
+ * Returns class name for the given color identifier
1067
+ * @param {string|number} color Color identifier
1068
+ * @returns {string} Class name
1069
+ */
1061
1070
 
1062
1071
 
1063
- const getClassNameByColor = color => {
1064
- if (options.colors && options.colors[color]) {
1065
- return options.colors[color];
1066
- }
1072
+ var getClassNameByColor = function getClassNameByColor(color) {
1073
+ if (options.colors && options.colors[color]) {
1074
+ return options.colors[color];
1075
+ }
1067
1076
 
1068
- return className;
1069
- };
1070
- /**
1071
- * Check if the given node is a wrapper
1072
- * @param {Node|Element} node
1073
- * @returns {boolean}
1074
- */
1077
+ return className;
1078
+ };
1079
+ /**
1080
+ * Check if the given node is a wrapper
1081
+ * @param {Node|Element} node
1082
+ * @returns {boolean}
1083
+ */
1075
1084
 
1076
1085
 
1077
- function isWrappingNode(node) {
1078
- return isElement(node) && node.tagName.toLowerCase() === 'span' && highlightingClasses.includes(node.className);
1079
- }
1080
- /**
1081
- * Check if the given node can be wrapped
1082
- * @param {Node} node
1083
- * @returns {boolean}
1084
- */
1086
+ function isWrappingNode(node) {
1087
+ return isElement(node) && node.tagName.toLowerCase() === 'span' && highlightingClasses.includes(node.className);
1088
+ }
1089
+ /**
1090
+ * Check if the given node can be wrapped
1091
+ * @param {Node} node
1092
+ * @returns {boolean}
1093
+ */
1085
1094
 
1086
1095
 
1087
- function isWrappable(node) {
1088
- return isText(node) && !isBlacklisted(node);
1089
- }
1090
- /**
1091
- * Check if the given node is, or is within, a blacklisted container.
1092
- * With `keepEmptyNodes` option, node inside blacklisted container can be whitelisted too.
1093
- * Priority of blacklist or whitelist is decided by which selector is closest to the node.
1094
- * If no match found, node is considered whitelisted.
1095
- * @param {Node} node
1096
- * @returns {boolean}
1097
- */
1096
+ function isWrappable(node) {
1097
+ return isText(node) && !isBlacklisted(node);
1098
+ }
1099
+ /**
1100
+ * Check if the given node is, or is within, a blacklisted container.
1101
+ * With `keepEmptyNodes` option, node inside blacklisted container can be whitelisted too.
1102
+ * Priority of blacklist or whitelist is decided by which selector is closest to the node.
1103
+ * If no match found, node is considered whitelisted.
1104
+ * @param {Node} node
1105
+ * @returns {boolean}
1106
+ */
1098
1107
 
1099
1108
 
1100
- function isBlacklisted(node) {
1101
- const closest = $(node).closest(containersBlackAndWhiteListSelector);
1109
+ function isBlacklisted(node) {
1110
+ var closest = $(node).closest(containersBlackAndWhiteListSelector);
1102
1111
 
1103
- if (!closest.length) {
1104
- return false;
1105
- } else if (!containersWhiteListSelector) {
1106
- return true;
1107
- } else {
1108
- return !closest.get(0).matches(containersWhiteListSelector);
1109
- }
1112
+ if (!closest.length) {
1113
+ return false;
1114
+ } else if (!containersWhiteListSelector) {
1115
+ return true;
1116
+ } else {
1117
+ return !closest.get(0).matches(containersWhiteListSelector);
1110
1118
  }
1111
- /**
1112
- * Wraps text node to the highlighter wrapper element
1113
- * @param {Node} textNode Text node to wrap
1114
- * @param {string} className Wrapper class name
1115
- * @param {number} groupId Group id
1116
- */
1119
+ }
1120
+ /**
1121
+ * Wraps text node to the highlighter wrapper element
1122
+ * @param {Node} textNode Text node to wrap
1123
+ * @param {string} className Wrapper class name
1124
+ * @param {number} groupId Group id
1125
+ */
1117
1126
 
1118
1127
 
1119
- function wrapNode(textNode, className, groupId) {
1120
- const element = getWrapper(groupId, className);
1121
- element.appendChild(textNode);
1122
- return element;
1123
- }
1124
- /**
1125
- * Create a wrapping node
1126
- * @param {number} groupId
1127
- * @returns {Element}
1128
- */
1128
+ function wrapNode(textNode, className, groupId) {
1129
+ var element = getWrapper(groupId, className);
1130
+ element.appendChild(textNode);
1131
+ return element;
1132
+ }
1133
+ /**
1134
+ * Create a wrapping node
1135
+ * @param {number} groupId
1136
+ * @returns {Element}
1137
+ */
1129
1138
 
1130
1139
 
1131
- function getWrapper(groupId, wrapperClass) {
1132
- const wrapper = document.createElement('span');
1133
- wrapper.className = wrapperClass || className;
1134
- wrapper.setAttribute(GROUP_ATTR, `${groupId}`);
1135
- return wrapper;
1136
- }
1137
- /**
1138
- * Returns the first unused group Id
1139
- * @returns {number}
1140
- */
1140
+ function getWrapper(groupId, wrapperClass) {
1141
+ var wrapper = document.createElement('span');
1142
+ wrapper.className = wrapperClass || className;
1143
+ wrapper.setAttribute(GROUP_ATTR, "".concat(groupId));
1144
+ return wrapper;
1145
+ }
1146
+ /**
1147
+ * Returns the first unused group Id
1148
+ * @returns {number}
1149
+ */
1141
1150
 
1142
1151
 
1143
- function getAvailableGroupId() {
1144
- var id = currentGroupId || 1;
1152
+ function getAvailableGroupId() {
1153
+ var id = currentGroupId || 1;
1145
1154
 
1146
- while ($(getContainer()).find('[' + GROUP_ATTR + '=' + id + ']').length !== 0) {
1147
- id++;
1148
- }
1149
-
1150
- return id;
1155
+ while ($(getContainer()).find('[' + GROUP_ATTR + '=' + id + ']').length !== 0) {
1156
+ id++;
1151
1157
  }
1152
- /**
1153
- * Check if the given node is an element
1154
- * @param {Node} node
1155
- * @returns {boolean}
1156
- */
1157
-
1158
1158
 
1159
- function isElement(node) {
1160
- return node && typeof node === 'object' && node.nodeType === window.Node.ELEMENT_NODE;
1161
- }
1162
- /**
1163
- * Check if the given node is of type text
1164
- * @param {Node} node
1165
- * @returns {boolean}
1166
- */
1159
+ return id;
1160
+ }
1161
+ /**
1162
+ * Check if the given node is an element
1163
+ * @param {Node} node
1164
+ * @returns {boolean}
1165
+ */
1167
1166
 
1168
1167
 
1169
- function isText(node) {
1170
- return node && typeof node === 'object' && node.nodeType === window.Node.TEXT_NODE;
1171
- }
1172
- /**
1173
- * a "Hot Node" is either wrappable text node or a wrapper
1174
- * @param {Node} node
1175
- * @returns {boolean}
1176
- */
1168
+ function isElement(node) {
1169
+ return node && _typeof(node) === 'object' && node.nodeType === window.Node.ELEMENT_NODE;
1170
+ }
1171
+ /**
1172
+ * Check if the given node is of type text
1173
+ * @param {Node} node
1174
+ * @returns {boolean}
1175
+ */
1177
1176
 
1178
1177
 
1179
- function isHotNode(node) {
1180
- return isWrappingNode(node) || isWrappable(node);
1181
- }
1182
- /**
1183
- * Public API of the highlighter helper
1184
- */
1178
+ function isText(node) {
1179
+ return node && _typeof(node) === 'object' && node.nodeType === window.Node.TEXT_NODE;
1180
+ }
1181
+ /**
1182
+ * a "Hot Node" is either wrappable text node or a wrapper
1183
+ * @param {Node} node
1184
+ * @returns {boolean}
1185
+ */
1185
1186
 
1186
1187
 
1187
- return {
1188
- highlightRanges: highlightRanges,
1189
- highlightFromIndex: highlightFromIndex,
1190
- getHighlightIndex: getHighlightIndex,
1191
- clearHighlights: clearHighlights,
1192
- clearSingleHighlight: clearSingleHighlight,
1193
- setActiveColor
1194
- };
1188
+ function isHotNode(node) {
1189
+ return isWrappingNode(node) || isWrappable(node);
1195
1190
  }
1191
+ /**
1192
+ * Public API of the highlighter helper
1193
+ */
1194
+
1195
+
1196
+ return {
1197
+ highlightRanges: highlightRanges,
1198
+ highlightFromIndex: highlightFromIndex,
1199
+ getHighlightIndex: getHighlightIndex,
1200
+ clearHighlights: clearHighlights,
1201
+ clearSingleHighlight: clearSingleHighlight,
1202
+ setActiveColor: setActiveColor
1203
+ };
1204
+ }
1196
1205
 
1197
- return highlighter;
1206
+ return highlighter;
1198
1207
 
1199
1208
  });