@internetarchive/bookreader 5.0.0-7 → 5.0.0-70-a1
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.
- package/.eslintrc.js +17 -15
- package/.github/workflows/node.js.yml +73 -10
- package/.github/workflows/npm-publish.yml +6 -20
- package/.testcaferc.js +10 -0
- package/BookReader/BookReader.css +396 -1129
- package/BookReader/BookReader.js +1 -1
- package/BookReader/BookReader.js.LICENSE.txt +20 -20
- package/BookReader/BookReader.js.map +1 -1
- package/BookReader/ia-bookreader-bundle.js +1788 -0
- package/BookReader/ia-bookreader-bundle.js.LICENSE.txt +19 -0
- package/BookReader/ia-bookreader-bundle.js.map +1 -0
- package/BookReader/icons/1up.svg +1 -1
- package/BookReader/icons/2up.svg +1 -1
- package/BookReader/icons/advance.svg +1 -1
- package/BookReader/icons/chevron-right.svg +1 -1
- package/BookReader/icons/close-circle-dark.svg +1 -1
- package/BookReader/icons/close-circle.svg +1 -1
- package/BookReader/icons/fullscreen.svg +1 -1
- package/BookReader/icons/fullscreen_exit.svg +1 -1
- package/BookReader/icons/hamburger.svg +1 -1
- package/BookReader/icons/left-arrow.svg +1 -1
- package/BookReader/icons/magnify-minus.svg +1 -1
- package/BookReader/icons/magnify-plus.svg +1 -1
- package/BookReader/icons/magnify.svg +1 -1
- package/BookReader/icons/pause.svg +1 -1
- package/BookReader/icons/play.svg +1 -1
- package/BookReader/icons/playback-speed.svg +1 -1
- package/BookReader/icons/read-aloud.svg +1 -1
- package/BookReader/icons/review.svg +1 -1
- package/BookReader/icons/thumbnails.svg +1 -1
- package/BookReader/icons/voice.svg +1 -0
- package/BookReader/icons/volume-full.svg +1 -1
- package/BookReader/images/BRicons.svg +3 -3
- package/BookReader/images/books_graphic.svg +1 -1
- package/BookReader/images/icon_book.svg +1 -1
- package/BookReader/images/icon_bookmark.svg +1 -1
- package/BookReader/images/icon_gear.svg +1 -1
- package/BookReader/images/icon_hamburger.svg +1 -1
- package/BookReader/images/icon_home.svg +1 -1
- package/BookReader/images/icon_info.svg +1 -1
- package/BookReader/images/icon_one_page.svg +1 -1
- package/BookReader/images/icon_pause.svg +1 -1
- package/BookReader/images/icon_play.svg +1 -1
- package/BookReader/images/icon_playback-rate.svg +1 -1
- package/BookReader/images/icon_search_button.svg +1 -1
- package/BookReader/images/icon_share.svg +1 -1
- package/BookReader/images/icon_skip-ahead.svg +1 -1
- package/BookReader/images/icon_skip-back.svg +1 -1
- package/BookReader/images/icon_speaker.svg +1 -1
- package/BookReader/images/icon_speaker_open.svg +1 -1
- package/BookReader/images/icon_thumbnails.svg +1 -1
- package/BookReader/images/icon_toc.svg +1 -1
- package/BookReader/images/icon_two_pages.svg +1 -1
- package/BookReader/images/marker_chap-off.svg +1 -1
- package/BookReader/images/marker_chap-on.svg +1 -1
- package/BookReader/images/marker_srch-on.svg +1 -1
- package/BookReader/jquery-3.js +2 -0
- package/BookReader/jquery-3.js.LICENSE.txt +24 -0
- package/BookReader/plugins/plugin.archive_analytics.js +1 -1
- package/BookReader/plugins/plugin.archive_analytics.js.map +1 -1
- package/BookReader/plugins/plugin.autoplay.js +1 -1
- package/BookReader/plugins/plugin.autoplay.js.map +1 -1
- package/BookReader/plugins/plugin.chapters.js +25 -1
- package/BookReader/plugins/plugin.chapters.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.chapters.js.map +1 -1
- package/BookReader/plugins/plugin.iframe.js +1 -1
- package/BookReader/plugins/plugin.iframe.js.map +1 -1
- package/BookReader/plugins/plugin.resume.js +1 -1
- package/BookReader/plugins/plugin.resume.js.map +1 -1
- package/BookReader/plugins/plugin.search.js +2 -1
- package/BookReader/plugins/plugin.search.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.search.js.map +1 -1
- package/BookReader/plugins/plugin.text_selection.js +2 -1
- package/BookReader/plugins/plugin.text_selection.js.LICENSE.txt +1 -0
- package/BookReader/plugins/plugin.text_selection.js.map +1 -1
- package/BookReader/plugins/plugin.tts.js +1 -1
- package/BookReader/plugins/plugin.tts.js.LICENSE.txt +2 -0
- package/BookReader/plugins/plugin.tts.js.map +1 -1
- package/BookReader/plugins/plugin.url.js +1 -1
- package/BookReader/plugins/plugin.url.js.map +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js +1 -1
- package/BookReader/plugins/plugin.vendor-fullscreen.js.map +1 -1
- package/BookReader/webcomponents-bundle.js +3 -0
- package/BookReader/webcomponents-bundle.js.LICENSE.txt +9 -0
- package/BookReader/webcomponents-bundle.js.map +1 -0
- package/BookReaderDemo/BookReaderDemo.css +16 -19
- package/BookReaderDemo/BookReaderJSAdvanced.js +0 -3
- package/BookReaderDemo/BookReaderJSAutoplay.js +4 -1
- package/BookReaderDemo/BookReaderJSSimple.js +1 -0
- package/BookReaderDemo/IADemoBr.js +147 -0
- package/BookReaderDemo/demo-advanced.html +2 -2
- package/BookReaderDemo/demo-autoplay.html +2 -3
- package/BookReaderDemo/demo-embed-iframe-src.html +2 -1
- package/BookReaderDemo/demo-fullscreen-mobile.html +3 -5
- package/BookReaderDemo/demo-fullscreen.html +2 -4
- package/BookReaderDemo/demo-iiif.html +2 -1
- package/BookReaderDemo/demo-iiif.js +0 -1
- package/BookReaderDemo/demo-internetarchive.html +213 -17
- package/BookReaderDemo/demo-multiple.html +2 -1
- package/BookReaderDemo/demo-preview-pages.html +2 -1
- package/BookReaderDemo/demo-simple.html +2 -1
- package/BookReaderDemo/demo-vendor-fullscreen.html +2 -4
- package/BookReaderDemo/ia-multiple-volumes-manifest.js +170 -0
- package/BookReaderDemo/immersion-1up.html +2 -2
- package/BookReaderDemo/immersion-mode.html +2 -4
- package/BookReaderDemo/toggle_controls.html +3 -2
- package/BookReaderDemo/view_mode.html +2 -1
- package/BookReaderDemo/viewmode-cycle.html +2 -3
- package/CHANGELOG.md +279 -0
- package/README.md +14 -1
- package/babel.config.js +20 -0
- package/codecov.yml +6 -0
- package/index.html +4 -1
- package/jsconfig.json +19 -0
- package/netlify.toml +9 -0
- package/package.json +69 -60
- package/renovate.json +52 -0
- package/scripts/preversion.js +4 -1
- package/src/BookNavigator/assets/bookmark-colors.js +1 -1
- package/src/BookNavigator/assets/button-base.js +4 -2
- package/src/BookNavigator/assets/ia-logo.js +17 -0
- package/src/BookNavigator/assets/icon_checkmark.js +1 -1
- package/src/BookNavigator/assets/icon_close.js +1 -1
- package/src/BookNavigator/book-navigator.js +586 -0
- package/src/BookNavigator/bookmarks/bookmark-button.js +3 -2
- package/src/BookNavigator/bookmarks/bookmark-edit.js +3 -4
- package/src/BookNavigator/bookmarks/bookmarks-list.js +2 -3
- package/src/BookNavigator/bookmarks/bookmarks-loginCTA.js +3 -8
- package/src/BookNavigator/bookmarks/bookmarks-provider.js +27 -17
- package/src/BookNavigator/bookmarks/ia-bookmarks.js +116 -67
- package/src/BookNavigator/delete-modal-actions.js +1 -1
- package/src/BookNavigator/downloads/downloads-provider.js +36 -21
- package/src/BookNavigator/downloads/downloads.js +41 -25
- package/src/BookNavigator/search/search-provider.js +49 -27
- package/src/BookNavigator/search/search-results.js +23 -9
- package/src/BookNavigator/sharing.js +27 -0
- package/src/BookNavigator/visual-adjustments/visual-adjustments-provider.js +11 -10
- package/src/BookNavigator/visual-adjustments/visual-adjustments.js +3 -3
- package/src/BookNavigator/volumes/volumes-provider.js +95 -0
- package/src/BookReader/BookModel.js +64 -34
- package/src/BookReader/DragScrollable.js +233 -0
- package/src/BookReader/Mode1Up.js +56 -351
- package/src/BookReader/Mode1UpLit.js +388 -0
- package/src/BookReader/Mode2Up.js +73 -1318
- package/src/BookReader/Mode2UpLit.js +776 -0
- package/src/BookReader/ModeCoordinateSpace.js +29 -0
- package/src/BookReader/ModeSmoothZoom.js +312 -0
- package/src/BookReader/ModeThumb.js +18 -12
- package/src/BookReader/Navbar/Navbar.js +12 -38
- package/src/BookReader/PageContainer.js +81 -6
- package/src/BookReader/ReduceSet.js +1 -1
- package/src/BookReader/Toolbar/Toolbar.js +10 -37
- package/src/BookReader/events.js +2 -3
- package/src/BookReader/options.js +24 -2
- package/src/BookReader/utils/HTMLDimensionsCacher.js +44 -0
- package/src/BookReader/utils/ScrollClassAdder.js +31 -0
- package/src/BookReader/utils/SelectionObserver.js +43 -0
- package/src/BookReader/utils.js +118 -13
- package/src/BookReader.js +423 -1056
- package/src/assets/icons/magnify-minus.svg +3 -7
- package/src/assets/icons/magnify-plus.svg +3 -7
- package/src/assets/icons/voice.svg +1 -0
- package/src/css/BookReader.scss +1 -5
- package/src/css/_BRBookmarks.scss +1 -1
- package/src/css/_BRComponent.scss +1 -1
- package/src/css/_BRmain.scss +16 -0
- package/src/css/_BRnav.scss +11 -38
- package/src/css/_BRpages.scss +149 -40
- package/src/css/_BRsearch.scss +67 -21
- package/src/css/_TextSelection.scss +87 -27
- package/src/css/_colorbox.scss +2 -2
- package/src/css/_controls.scss +20 -7
- package/src/css/_icons.scss +1 -1
- package/src/ia-bookreader/ia-bookreader.js +224 -0
- package/src/plugins/plugin.archive_analytics.js +3 -3
- package/src/plugins/plugin.autoplay.js +5 -11
- package/src/plugins/plugin.chapters.js +211 -186
- package/src/plugins/plugin.resume.js +3 -3
- package/src/plugins/plugin.text_selection.js +464 -134
- package/src/plugins/plugin.vendor-fullscreen.js +4 -4
- package/src/plugins/search/plugin.search.js +142 -125
- package/src/plugins/search/utils.js +43 -0
- package/src/plugins/search/view.js +33 -58
- package/src/plugins/tts/AbstractTTSEngine.js +46 -37
- package/src/plugins/tts/FestivalTTSEngine.js +13 -14
- package/src/plugins/tts/PageChunk.js +15 -21
- package/src/plugins/tts/PageChunkIterator.js +8 -12
- package/src/plugins/tts/WebTTSEngine.js +87 -71
- package/src/plugins/tts/plugin.tts.js +95 -126
- package/src/plugins/tts/utils.js +0 -25
- package/src/plugins/url/UrlPlugin.js +193 -0
- package/src/plugins/{plugin.url.js → url/plugin.url.js} +45 -16
- package/src/util/browserSniffing.js +22 -0
- package/src/util/docCookies.js +21 -2
- package/tests/e2e/README.md +37 -0
- package/tests/e2e/autoplay.test.js +2 -2
- package/tests/e2e/base.test.js +8 -16
- package/tests/e2e/helpers/base.js +53 -48
- package/tests/e2e/helpers/debug.js +1 -1
- package/tests/e2e/helpers/params.js +17 -0
- package/tests/e2e/helpers/rightToLeft.js +8 -14
- package/tests/e2e/helpers/search.js +73 -0
- package/tests/e2e/models/Navigation.js +20 -37
- package/tests/e2e/rightToLeft.test.js +4 -5
- package/tests/e2e/viewmode.test.js +40 -33
- package/tests/jest/BookNavigator/book-navigator.test.js +658 -0
- package/tests/jest/BookNavigator/bookmarks/bookmark-button.test.js +43 -0
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmark-edit.test.js +25 -26
- package/tests/{karma → jest}/BookNavigator/bookmarks/bookmarks-list.test.js +41 -42
- package/tests/jest/BookNavigator/bookmarks/ia-bookmarks.test.js +45 -0
- package/tests/jest/BookNavigator/downloads/downloads-provider.test.js +67 -0
- package/tests/jest/BookNavigator/downloads/downloads.test.js +53 -0
- package/tests/jest/BookNavigator/search/search-provider.test.js +167 -0
- package/tests/{karma → jest}/BookNavigator/search/search-results.test.js +109 -60
- package/tests/jest/BookNavigator/sharing/sharing-provider.test.js +49 -0
- package/tests/jest/BookNavigator/visual-adjustments.test.js +200 -0
- package/tests/jest/BookNavigator/volumes/volumes-provider.test.js +80 -0
- package/tests/{BookReader → jest/BookReader}/BookModel.test.js +74 -14
- package/tests/jest/BookReader/BookReaderPublicFunctions.test.js +193 -0
- package/tests/{BookReader → jest/BookReader}/ImageCache.test.js +4 -4
- package/tests/jest/BookReader/Mode1UpLit.test.js +73 -0
- package/tests/jest/BookReader/Mode2Up.test.js +98 -0
- package/tests/jest/BookReader/Mode2UpLit.test.js +190 -0
- package/tests/jest/BookReader/ModeCoordinateSpace.test.js +16 -0
- package/tests/jest/BookReader/ModeSmoothZoom.test.js +218 -0
- package/tests/jest/BookReader/ModeThumb.test.js +71 -0
- package/tests/{BookReader → jest/BookReader}/Navbar/Navbar.test.js +10 -10
- package/tests/{BookReader → jest/BookReader}/PageContainer.test.js +88 -6
- package/tests/{BookReader → jest/BookReader}/ReduceSet.test.js +1 -1
- package/tests/{BookReader → jest/BookReader}/Toolbar/Toolbar.test.js +2 -2
- package/tests/jest/BookReader/utils/HTMLDimensionsCacher.test.js +59 -0
- package/tests/jest/BookReader/utils/ScrollClassAdder.test.js +49 -0
- package/tests/jest/BookReader/utils/SelectionObserver.test.js +43 -0
- package/tests/{BookReader → jest/BookReader}/utils/classes.test.js +1 -1
- package/tests/jest/BookReader/utils.test.js +229 -0
- package/tests/jest/BookReader.keyboard.test.js +190 -0
- package/tests/{BookReader.options.test.js → jest/BookReader.options.test.js} +9 -1
- package/tests/{BookReader.test.js → jest/BookReader.test.js} +26 -37
- package/tests/{plugins → jest/plugins}/plugin.archive_analytics.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.autoplay.test.js +4 -4
- package/tests/jest/plugins/plugin.chapters.test.js +145 -0
- package/tests/{plugins → jest/plugins}/plugin.iframe.test.js +2 -2
- package/tests/{plugins → jest/plugins}/plugin.resume.test.js +3 -3
- package/tests/jest/plugins/plugin.text_selection.test.js +317 -0
- package/tests/{plugins → jest/plugins}/plugin.vendor-fullscreen.test.js +2 -2
- package/tests/{plugins → jest/plugins}/search/plugin.search.test.js +25 -47
- package/tests/{plugins → jest/plugins}/search/plugin.search.view.test.js +39 -6
- package/tests/jest/plugins/search/utils.js +25 -0
- package/tests/jest/plugins/search/utils.test.js +29 -0
- package/tests/{plugins → jest/plugins}/tts/AbstractTTSEngine.test.js +9 -9
- package/tests/{plugins → jest/plugins}/tts/FestivalTTSEngine.test.js +4 -4
- package/tests/{plugins → jest/plugins}/tts/PageChunk.test.js +1 -1
- package/tests/{plugins → jest/plugins}/tts/PageChunkIterator.test.js +3 -3
- package/tests/{plugins → jest/plugins}/tts/WebTTSEngine.test.js +47 -1
- package/tests/{plugins → jest/plugins}/tts/utils.test.js +1 -60
- package/tests/jest/plugins/url/UrlPlugin.test.js +190 -0
- package/tests/{plugins → jest/plugins/url}/plugin.url.test.js +53 -14
- package/tests/jest/setup.js +3 -0
- package/tests/{util → jest/util}/browserSniffing.test.js +1 -1
- package/tests/jest/util/docCookies.test.js +24 -0
- package/tests/{util → jest/util}/strings.test.js +1 -1
- package/tests/{utils.js → jest/utils.js} +38 -0
- package/webpack.config.js +11 -6
- package/.babelrc +0 -12
- package/.dependabot/config.yml +0 -6
- package/.testcaferc.json +0 -5
- package/BookReader/bookreader-component-bundle.js +0 -1450
- package/BookReader/bookreader-component-bundle.js.LICENSE.txt +0 -38
- package/BookReader/bookreader-component-bundle.js.map +0 -1
- package/BookReader/jquery-1.10.1.js +0 -2
- package/BookReader/jquery-1.10.1.js.LICENSE.txt +0 -24
- package/BookReader/plugins/plugin.menu_toggle.js +0 -2
- package/BookReader/plugins/plugin.menu_toggle.js.map +0 -1
- package/BookReader/plugins/plugin.mobile_nav.js +0 -2
- package/BookReader/plugins/plugin.mobile_nav.js.map +0 -1
- package/BookReaderDemo/bookreader-template-bundle.js +0 -7178
- package/BookReaderDemo/demo-plugin-menu-toggle.html +0 -34
- package/karma.conf.js +0 -23
- package/src/BookNavigator/BookModel.js +0 -14
- package/src/BookNavigator/BookNavigator.js +0 -446
- package/src/BookNavigator/assets/book-loader.js +0 -27
- package/src/BookNavigator/br-fullscreen-mgr.js +0 -83
- package/src/BookNavigator/search/a-search-result.js +0 -55
- package/src/BookReader/DebugConsole.js +0 -54
- package/src/BookReaderComponent/BookReaderComponent.js +0 -112
- package/src/ItemNavigator/ItemNavigator.js +0 -376
- package/src/ItemNavigator/providers/sharing.js +0 -29
- package/src/css/_MobileNav.scss +0 -194
- package/src/dragscrollable-br.js +0 -261
- package/src/plugins/menu_toggle/plugin.menu_toggle.js +0 -324
- package/src/plugins/plugin.mobile_nav.js +0 -287
- package/tests/BookReader/BookReaderPublicFunctions.test.js +0 -171
- package/tests/BookReader/DebugConsole.test.js +0 -25
- package/tests/BookReader/Mode1Up.test.js +0 -164
- package/tests/BookReader/Mode2Up.test.js +0 -247
- package/tests/BookReader/utils.test.js +0 -109
- package/tests/e2e/helpers/desktopSearch.js +0 -72
- package/tests/e2e/helpers/mobileSearch.js +0 -85
- package/tests/e2e/ia-production/ia-prod-base.js +0 -17
- package/tests/karma/BookNavigator/book-navigator.test.js +0 -132
- package/tests/karma/BookNavigator/search/search-provider.test.js +0 -23
- package/tests/karma/BookNavigator/visual-adjustments.test.js +0 -201
- package/tests/plugins/menu_toggle/plugin.menu_toggle.test.js +0 -68
- package/tests/plugins/plugin.chapters.test.js +0 -130
- package/tests/plugins/plugin.mobile_nav.test.js +0 -66
- package/tests/plugins/plugin.text_selection.test.js +0 -203
- package/tests/util/docCookies.test.js +0 -15
@@ -56,7 +56,7 @@ if (!isMobile()) {
|
|
56
56
|
$(document.body).append(cboxOverlay).append(cbox);
|
57
57
|
}
|
58
58
|
});
|
59
|
-
}
|
59
|
+
};
|
60
60
|
})(BookReader.prototype.init);
|
61
61
|
|
62
62
|
/**
|
@@ -92,7 +92,7 @@ if (!isMobile()) {
|
|
92
92
|
$(document).off('keyup' + EVENT_NAMESPACE);
|
93
93
|
|
94
94
|
this.isFullscreenActive = false;
|
95
|
-
this.updateBrClasses()
|
95
|
+
this.updateBrClasses();
|
96
96
|
|
97
97
|
this.resize();
|
98
98
|
this.refs.$brContainer.animate({ opacity: 1 }, 400, 'linear');
|
@@ -233,8 +233,8 @@ export function bindFullscreenChangeListener(
|
|
233
233
|
'moz',
|
234
234
|
'ms'
|
235
235
|
];
|
236
|
-
const all_events =
|
237
|
-
$(document).
|
236
|
+
const all_events = (event + vendor_prefixes.join(event) + event).trim();
|
237
|
+
$(document).on(all_events, data, fullscreenchangeListener);
|
238
238
|
}
|
239
239
|
|
240
240
|
/**
|
@@ -1,9 +1,7 @@
|
|
1
|
+
// @ts-check
|
1
2
|
/* global BookReader */
|
2
3
|
/**
|
3
4
|
* Plugin for Archive.org book search
|
4
|
-
* NOTE: This script must be loaded AFTER `plugin.mobile_nav.js`
|
5
|
-
* as it mutates mobile nav drawer
|
6
|
-
*
|
7
5
|
* Events fired at various points throughout search processing are published
|
8
6
|
* on the document DOM element. These can be subscribed to using jQuery's event
|
9
7
|
* binding method `$.fn.on`. All of the events are prefixed with a BookReader
|
@@ -23,7 +21,14 @@
|
|
23
21
|
* @event BookReader:SearchCanceled - When no results found. Receives
|
24
22
|
* `instance`
|
25
23
|
*/
|
24
|
+
import { poll } from '../../BookReader/utils.js';
|
25
|
+
import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
|
26
26
|
import SearchView from './view.js';
|
27
|
+
import { marshallSearchResults } from './utils.js';
|
28
|
+
/** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */
|
29
|
+
/** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */
|
30
|
+
/** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */
|
31
|
+
/** @typedef {import('../../BookReader/BookModel').PageNumString} PageNumString */
|
27
32
|
|
28
33
|
jQuery.extend(BookReader.defaultOptions, {
|
29
34
|
server: 'ia600609.us.archive.org',
|
@@ -31,7 +36,10 @@ jQuery.extend(BookReader.defaultOptions, {
|
|
31
36
|
subPrefix: '',
|
32
37
|
bookPath: '',
|
33
38
|
enableSearch: true,
|
39
|
+
searchInsideProtocol: 'https',
|
34
40
|
searchInsideUrl: '/fulltext/inside.php',
|
41
|
+
searchInsidePreTag: '{{{',
|
42
|
+
searchInsidePostTag: '}}}',
|
35
43
|
initialSearchTerm: null,
|
36
44
|
});
|
37
45
|
|
@@ -44,7 +52,6 @@ BookReader.prototype.setup = (function (super_) {
|
|
44
52
|
this.searchResults = null;
|
45
53
|
this.searchInsideUrl = options.searchInsideUrl;
|
46
54
|
this.enableSearch = options.enableSearch;
|
47
|
-
this.goToFirstResult = false;
|
48
55
|
|
49
56
|
// Base server used by some api calls
|
50
57
|
this.bookId = options.bookId;
|
@@ -56,14 +63,10 @@ BookReader.prototype.setup = (function (super_) {
|
|
56
63
|
this._cancelSearch.bind(this);
|
57
64
|
this.cancelSearchRequest.bind(this);
|
58
65
|
|
59
|
-
|
60
|
-
this.
|
61
|
-
|
62
|
-
|
63
|
-
this._cancelSearch();
|
64
|
-
this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
|
65
|
-
}
|
66
|
-
});
|
66
|
+
/** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
|
67
|
+
this._searchBoxesByIndex = {};
|
68
|
+
|
69
|
+
this.searchView = undefined;
|
67
70
|
};
|
68
71
|
})(BookReader.prototype.setup);
|
69
72
|
|
@@ -71,11 +74,26 @@ BookReader.prototype.setup = (function (super_) {
|
|
71
74
|
BookReader.prototype.init = (function (super_) {
|
72
75
|
return function () {
|
73
76
|
super_.call(this);
|
74
|
-
|
77
|
+
// give SearchView the most complete bookreader state
|
78
|
+
this.searchView = new SearchView({
|
79
|
+
br: this,
|
80
|
+
searchCancelledCallback: () => {
|
81
|
+
this._cancelSearch();
|
82
|
+
this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
|
83
|
+
}
|
84
|
+
});
|
75
85
|
if (this.options.enableSearch && this.options.initialSearchTerm) {
|
86
|
+
/**
|
87
|
+
* this.search() take two parameter
|
88
|
+
* 1. this.options.initialSearchTerm - search term
|
89
|
+
* 2. {
|
90
|
+
* goToFirstResult: this.options.goToFirstResult,
|
91
|
+
* suppressFragmentChange: false // always want to change fragment in URL
|
92
|
+
* }
|
93
|
+
*/
|
76
94
|
this.search(
|
77
95
|
this.options.initialSearchTerm,
|
78
|
-
{ goToFirstResult: this.goToFirstResult, suppressFragmentChange:
|
96
|
+
{ goToFirstResult: this.options.goToFirstResult, suppressFragmentChange: false }
|
79
97
|
);
|
80
98
|
}
|
81
99
|
};
|
@@ -93,6 +111,25 @@ BookReader.prototype.buildToolbarElement = (function (super_) {
|
|
93
111
|
};
|
94
112
|
})(BookReader.prototype.buildToolbarElement);
|
95
113
|
|
114
|
+
/** @override */
|
115
|
+
BookReader.prototype._createPageContainer = (function (super_) {
|
116
|
+
return function (index) {
|
117
|
+
const pageContainer = super_.call(this, index);
|
118
|
+
if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {
|
119
|
+
const pageIndex = pageContainer.page.index;
|
120
|
+
const boxes = this._searchBoxesByIndex[pageIndex];
|
121
|
+
renderBoxesInPageContainerLayer(
|
122
|
+
'searchHiliteLayer',
|
123
|
+
boxes,
|
124
|
+
pageContainer.page,
|
125
|
+
pageContainer.$container[0],
|
126
|
+
boxes.map(b => `match-index-${b.matchIndex}`),
|
127
|
+
);
|
128
|
+
}
|
129
|
+
return pageContainer;
|
130
|
+
};
|
131
|
+
})(BookReader.prototype._createPageContainer);
|
132
|
+
|
96
133
|
/**
|
97
134
|
* @typedef {object} SearchOptions
|
98
135
|
* @property {boolean} goToFirstResult
|
@@ -107,7 +144,7 @@ BookReader.prototype.buildToolbarElement = (function (super_) {
|
|
107
144
|
* @param {string} term
|
108
145
|
* @param {SearchOptions} overrides
|
109
146
|
*/
|
110
|
-
BookReader.prototype.search = function(term = '', overrides = {}) {
|
147
|
+
BookReader.prototype.search = async function(term = '', overrides = {}) {
|
111
148
|
/** @type {SearchOptions} */
|
112
149
|
const defaultOptions = {
|
113
150
|
goToFirstResult: false, /* jump to the first result (default=false) */
|
@@ -119,6 +156,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
|
|
119
156
|
};
|
120
157
|
const options = jQuery.extend({}, defaultOptions, overrides);
|
121
158
|
this.suppressFragmentChange = options.suppressFragmentChange;
|
159
|
+
this.searchCancelled = false;
|
122
160
|
|
123
161
|
// strip slashes, since this goes in the url
|
124
162
|
this.searchTerm = term.replace(/\//g, ' ');
|
@@ -133,7 +171,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
|
|
133
171
|
|
134
172
|
// Remove the port and userdir
|
135
173
|
const serverPath = this.server.replace(/:.+/, '');
|
136
|
-
const baseUrl =
|
174
|
+
const baseUrl = `${this.options.searchInsideProtocol}://${serverPath}${this.searchInsideUrl}?`;
|
137
175
|
|
138
176
|
// Remove subPrefix from end of path
|
139
177
|
let path = this.bookPath;
|
@@ -147,6 +185,8 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
|
|
147
185
|
doc: this.subPrefix,
|
148
186
|
path,
|
149
187
|
q: term,
|
188
|
+
pre_tag: this.options.searchInsidePreTag,
|
189
|
+
post_tag: this.options.searchInsidePostTag,
|
150
190
|
};
|
151
191
|
|
152
192
|
// NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work
|
@@ -154,13 +194,8 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
|
|
154
194
|
|
155
195
|
const url = `${baseUrl}${paramStr}`;
|
156
196
|
|
157
|
-
const
|
158
|
-
this.
|
159
|
-
window.BRSearchInProgress = () => {};
|
160
|
-
};
|
161
|
-
|
162
|
-
const processSearchResults = (searchInsideResults) => {
|
163
|
-
if (!this.searchXHR) {
|
197
|
+
const callSearchResultsCallback = (searchInsideResults) => {
|
198
|
+
if (this.searchCancelled) {
|
164
199
|
return;
|
165
200
|
}
|
166
201
|
const responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
|
@@ -168,6 +203,7 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
|
|
168
203
|
const hasCustomSuccess = typeof options.success === 'function';
|
169
204
|
|
170
205
|
if (responseHasError) {
|
206
|
+
console.error('Search Inside Response Error', searchInsideResults.error || 'matches.length == 0');
|
171
207
|
hasCustomError
|
172
208
|
? options.error.call(this, searchInsideResults, options)
|
173
209
|
: this.BRSearchCallbackError(searchInsideResults, options);
|
@@ -176,21 +212,15 @@ BookReader.prototype.search = function(term = '', overrides = {}) {
|
|
176
212
|
? options.success.call(this, searchInsideResults, options)
|
177
213
|
: this.BRSearchCallback(searchInsideResults, options);
|
178
214
|
}
|
179
|
-
cleanup();
|
180
|
-
};
|
181
|
-
|
182
|
-
const beforeSend = (xhr) => {
|
183
|
-
this.searchXHR = xhr;
|
184
|
-
window.BRSearchInProgress = processSearchResults;
|
185
215
|
};
|
186
216
|
|
187
217
|
this.trigger('SearchStarted', { term: this.searchTerm, instance: this });
|
188
|
-
|
218
|
+
callSearchResultsCallback(await $.ajax({
|
189
219
|
url: url,
|
190
220
|
dataType: 'jsonp',
|
191
|
-
|
192
|
-
|
193
|
-
})
|
221
|
+
cache: true,
|
222
|
+
beforeSend: xhr => { this.searchXHR = xhr; },
|
223
|
+
}));
|
194
224
|
};
|
195
225
|
|
196
226
|
/**
|
@@ -202,21 +232,22 @@ BookReader.prototype._cancelSearch = function () {
|
|
202
232
|
this.searchView.clearSearchFieldAndResults(false);
|
203
233
|
this.searchTerm = '';
|
204
234
|
this.searchXHR = null;
|
235
|
+
this.searchCancelled = true;
|
205
236
|
this.searchResults = [];
|
206
|
-
|
207
|
-
}
|
237
|
+
};
|
208
238
|
|
209
239
|
/**
|
210
240
|
* External function to cancel search
|
211
241
|
* checks for term & xhr in flight before running
|
212
242
|
*/
|
213
243
|
BookReader.prototype.cancelSearchRequest = function () {
|
244
|
+
this.searchCancelled = true;
|
214
245
|
if (this.searchXHR !== null) {
|
215
246
|
this._cancelSearch();
|
216
247
|
this.searchView.toggleSearchPending();
|
217
248
|
this.trigger('SearchCanceled', { term: this.searchTerm, instance: this });
|
218
249
|
}
|
219
|
-
}
|
250
|
+
};
|
220
251
|
|
221
252
|
/**
|
222
253
|
* @typedef {object} SearchInsideMatchBox
|
@@ -226,10 +257,14 @@ BookReader.prototype.cancelSearchRequest = function () {
|
|
226
257
|
* @property {number} b
|
227
258
|
* @property {number} t
|
228
259
|
* @property {HTMLDivElement} [div]
|
260
|
+
* @property {number} matchIndex This is a fake field! not part of the API response. The index of the match that contains this box in total search results matches.
|
229
261
|
*/
|
230
262
|
|
231
263
|
/**
|
232
264
|
* @typedef {object} SearchInsideMatch
|
265
|
+
* @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.
|
266
|
+
* @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.
|
267
|
+
* @property {string} html (computed field) The html-escaped raw html to display in the UI.
|
233
268
|
* @property {string} text
|
234
269
|
* @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
|
235
270
|
*/
|
@@ -243,21 +278,26 @@ BookReader.prototype.cancelSearchRequest = function () {
|
|
243
278
|
|
244
279
|
/**
|
245
280
|
* Search Results return handler
|
246
|
-
* @callback
|
247
281
|
* @param {SearchInsideResults} results
|
248
282
|
* @param {object} options
|
249
283
|
* @param {boolean} options.goToFirstResult
|
250
284
|
*/
|
251
285
|
BookReader.prototype.BRSearchCallback = function(results, options) {
|
286
|
+
marshallSearchResults(
|
287
|
+
results,
|
288
|
+
pageNum => this.book.getPageNum(this.book.leafNumToIndex(pageNum)),
|
289
|
+
this.options.searchInsidePreTag,
|
290
|
+
this.options.searchInsidePostTag,
|
291
|
+
);
|
252
292
|
this.searchResults = results || [];
|
253
293
|
|
254
294
|
this.updateSearchHilites();
|
255
295
|
this.removeProgressPopup();
|
256
296
|
if (options.goToFirstResult) {
|
257
|
-
this._searchPluginGoToResult(
|
297
|
+
this._searchPluginGoToResult(0);
|
258
298
|
}
|
259
299
|
this.trigger('SearchCallback', { results, options, instance: this });
|
260
|
-
}
|
300
|
+
};
|
261
301
|
|
262
302
|
/**
|
263
303
|
* Main search results error handler
|
@@ -297,95 +337,41 @@ BookReader.prototype._BRSearchCallbackError = function(results) {
|
|
297
337
|
* updates search on-page highlights controller
|
298
338
|
*/
|
299
339
|
BookReader.prototype.updateSearchHilites = function() {
|
300
|
-
|
301
|
-
|
302
|
-
|
340
|
+
/** @type {SearchInsideMatch[]} */
|
341
|
+
const matches = this.searchResults?.matches || [];
|
342
|
+
/** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
|
343
|
+
const boxesByIndex = {};
|
344
|
+
|
345
|
+
// Clear any existing svg layers
|
346
|
+
this.removeSearchHilites();
|
347
|
+
|
348
|
+
// Group by pageIndex
|
349
|
+
for (const match of matches) {
|
350
|
+
for (const box of match.par[0].boxes) {
|
351
|
+
const pageIndex = this.book.leafNumToIndex(box.page);
|
352
|
+
const pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);
|
353
|
+
pageBoxes.push(box);
|
354
|
+
}
|
303
355
|
}
|
304
|
-
this.updateSearchHilites1UP();
|
305
|
-
};
|
306
|
-
|
307
|
-
/**
|
308
|
-
* update search on-page highlights in 1up mode
|
309
|
-
*/
|
310
|
-
BookReader.prototype.updateSearchHilites1UP = function() {
|
311
|
-
const results = this.searchResults;
|
312
|
-
if (null == results) return;
|
313
|
-
results.matches?.forEach(match => {
|
314
|
-
match.par[0].boxes.forEach(box => {
|
315
|
-
const pageIndex = this.leafNumToIndex(box.page);
|
316
|
-
const pageIsInView = jQuery.inArray(pageIndex, this.displayedIndices) >= 0;
|
317
|
-
if (pageIsInView) {
|
318
|
-
if (!box.div) {
|
319
|
-
//create a div for the search highlight, and stash it in the box object
|
320
|
-
box.div = document.createElement('div');
|
321
|
-
$(box.div).prop('className', 'BookReaderSearchHilite').appendTo(this.$(`.pagediv${pageIndex}`));
|
322
|
-
}
|
323
|
-
const page = this._models.book.getPage(pageIndex);
|
324
|
-
const highlight = {
|
325
|
-
width: this._modes.mode1Up.physicalInchesToDisplayPixels((box.r - box.l) / page.ppi),
|
326
|
-
height: this._modes.mode1Up.physicalInchesToDisplayPixels((box.b - box.t) / page.ppi),
|
327
|
-
left: this._modes.mode1Up.physicalInchesToDisplayPixels(box.l / page.ppi),
|
328
|
-
top: this._modes.mode1Up.physicalInchesToDisplayPixels(box.t / page.ppi),
|
329
|
-
};
|
330
|
-
$(box.div).css(highlight);
|
331
|
-
} else {
|
332
|
-
if (box.div) {
|
333
|
-
$(box.div).remove();
|
334
|
-
box.div = null;
|
335
|
-
}
|
336
|
-
}
|
337
|
-
});
|
338
|
-
});
|
339
|
-
};
|
340
356
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
357
|
+
// update any already created pages
|
358
|
+
for (const [pageIndexString, boxes] of Object.entries(boxesByIndex)) {
|
359
|
+
const pageIndex = parseFloat(pageIndexString);
|
360
|
+
const page = this.book.getPage(pageIndex);
|
361
|
+
const pageContainers = this.getActivePageContainerElementsForIndex(pageIndex);
|
362
|
+
for (const container of pageContainers) {
|
363
|
+
renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => `match-index-${b.matchIndex}`));
|
364
|
+
}
|
365
|
+
}
|
346
366
|
|
347
|
-
|
348
|
-
|
349
|
-
const { matches = [] } = results;
|
350
|
-
matches.forEach((match) => {
|
351
|
-
match.par[0].boxes.forEach(box => {
|
352
|
-
const pageIndex = this.leafNumToIndex(match.par[0].page);
|
353
|
-
const pageIsInView = jQuery.inArray(pageIndex, this.displayedIndices) >= 0;
|
354
|
-
const { isViewable } = this._models.book.getPage(pageIndex);
|
355
|
-
|
356
|
-
if (pageIsInView && isViewable) {
|
357
|
-
if (!box.div) {
|
358
|
-
//create a div for the search highlight, and stash it in the box object
|
359
|
-
box.div = document.createElement('div');
|
360
|
-
$(box.div).addClass('BookReaderSearchHilite')
|
361
|
-
.appendTo(this.refs.$brTwoPageView);
|
362
|
-
}
|
363
|
-
this.setHilightCss2UP(box.div, pageIndex, box.l, box.r, box.t, box.b);
|
364
|
-
} else {
|
365
|
-
// clear stale reference
|
366
|
-
if (box.div) {
|
367
|
-
$(box.div).remove();
|
368
|
-
box.div = null;
|
369
|
-
}
|
370
|
-
}
|
371
|
-
});
|
372
|
-
});
|
367
|
+
this._searchBoxesByIndex = boxesByIndex;
|
373
368
|
};
|
374
369
|
|
375
370
|
/**
|
376
371
|
* remove search highlights
|
377
372
|
*/
|
378
373
|
BookReader.prototype.removeSearchHilites = function() {
|
379
|
-
|
380
|
-
if (null == results || !results.matches) { return; }
|
381
|
-
results.matches.forEach(match => {
|
382
|
-
match.par[0].boxes.forEach(box => {
|
383
|
-
if (null != box.div) {
|
384
|
-
$(box.div).remove();
|
385
|
-
box.div = null;
|
386
|
-
}
|
387
|
-
});
|
388
|
-
});
|
374
|
+
$(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();
|
389
375
|
};
|
390
376
|
|
391
377
|
/**
|
@@ -393,11 +379,14 @@ BookReader.prototype.removeSearchHilites = function() {
|
|
393
379
|
* Goes to the page specified. If the page is not viewable, tries to load the page
|
394
380
|
* FIXME Most of this logic is IA specific, and should be less integrated into here
|
395
381
|
* or at least more configurable.
|
396
|
-
* @param {
|
382
|
+
* @param {number} matchIndex
|
397
383
|
*/
|
398
|
-
BookReader.prototype._searchPluginGoToResult = async function (
|
399
|
-
const
|
384
|
+
BookReader.prototype._searchPluginGoToResult = async function (matchIndex) {
|
385
|
+
const match = this.searchResults?.matches[matchIndex];
|
386
|
+
const book = this.book;
|
387
|
+
const pageIndex = book.leafNumToIndex(match.par[0].page);
|
400
388
|
const page = book.getPage(pageIndex);
|
389
|
+
const onNearbyPage = Math.abs(this.currentIndex() - pageIndex) < 3;
|
401
390
|
let makeUnviewableAtEnd = false;
|
402
391
|
if (!page.isViewable) {
|
403
392
|
const resp = await fetch('/services/bookreader/request_page?' + new URLSearchParams({
|
@@ -416,15 +405,43 @@ BookReader.prototype._searchPluginGoToResult = async function (pageIndex) {
|
|
416
405
|
book.getPage(pageIndex).makeViewable();
|
417
406
|
makeUnviewableAtEnd = true;
|
418
407
|
}
|
408
|
+
|
409
|
+
// Trigger an update of book
|
410
|
+
this._modes.mode1Up.mode1UpLit.updatePages();
|
411
|
+
if (this.activeMode == this._modes.mode1Up) {
|
412
|
+
await this._modes.mode1Up.mode1UpLit.updateComplete;
|
413
|
+
}
|
419
414
|
}
|
420
415
|
/* this updates the URL */
|
421
|
-
this.
|
422
|
-
|
416
|
+
if (!this._isIndexDisplayed(pageIndex)) {
|
417
|
+
this.suppressFragmentChange = false;
|
418
|
+
this.jumpToIndex(pageIndex);
|
419
|
+
}
|
423
420
|
|
424
421
|
// Reset it to unviewable if it wasn't resolved
|
425
422
|
if (makeUnviewableAtEnd) {
|
426
423
|
book.getPage(pageIndex).makeViewable(false);
|
427
424
|
}
|
425
|
+
|
426
|
+
// Scroll/flash in the ui
|
427
|
+
const $boxes = await poll(() => $(`rect.match-index-${match.matchIndex}`), { until: result => result.length > 0 });
|
428
|
+
if ($boxes.length) {
|
429
|
+
$boxes.css('animation', 'none');
|
430
|
+
$boxes[0].scrollIntoView({
|
431
|
+
// Only vertically center the highlight if we're in 1up or in full screen. In
|
432
|
+
// 2up, if we're not fullscreen, the whole body gets scrolled around to try to
|
433
|
+
// center the highlight 🙄 See:
|
434
|
+
// https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
|
435
|
+
// Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
|
436
|
+
// full-width, and covers up the last line of the highlight.
|
437
|
+
block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',
|
438
|
+
inline: 'center',
|
439
|
+
behavior: onNearbyPage ? 'smooth' : 'auto',
|
440
|
+
});
|
441
|
+
// wait for animation to start
|
442
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
443
|
+
$boxes.removeAttr("style");
|
444
|
+
}
|
428
445
|
};
|
429
446
|
|
430
447
|
/**
|
@@ -458,7 +475,7 @@ BookReader.prototype.searchHighlightVisible = function() {
|
|
458
475
|
|
459
476
|
results.matches.some(match => {
|
460
477
|
return match.par[0].boxes.some(box => {
|
461
|
-
const pageIndex = this.leafNumToIndex(box.page);
|
478
|
+
const pageIndex = this.book.leafNumToIndex(box.page);
|
462
479
|
if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
|
463
480
|
return true;
|
464
481
|
}
|
@@ -0,0 +1,43 @@
|
|
1
|
+
import { escapeHTML, escapeRegExp } from '../../BookReader/utils.js';
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @param {string} match
|
5
|
+
* @param {string} preTag
|
6
|
+
* @param {string} postTag
|
7
|
+
* @returns {string}
|
8
|
+
*/
|
9
|
+
export function renderMatch(match, preTag, postTag) {
|
10
|
+
// Search results are returned as a text blob with the hits wrapped in
|
11
|
+
// triple mustaches. Hits occasionally include text beyond the search
|
12
|
+
// term, so everything within the staches is captured and wrapped.
|
13
|
+
const preTagRe = escapeRegExp(escapeHTML(preTag));
|
14
|
+
const postTagRe = escapeRegExp(escapeHTML(postTag));
|
15
|
+
// [^] matches any character, including line breaks
|
16
|
+
const regex = new RegExp(`${preTagRe}([^]+?)${postTagRe}`, 'g');
|
17
|
+
return escapeHTML(match)
|
18
|
+
.replace(regex, '<mark>$1</mark>')
|
19
|
+
// Fix trailing hyphens. This over-corrects but is net useful.
|
20
|
+
.replace(/(\b)- /g, '$1');
|
21
|
+
}
|
22
|
+
|
23
|
+
/**
|
24
|
+
* Attach some fields to search inside results
|
25
|
+
* @param {SearchInsideResults} results
|
26
|
+
* @param {(pageNum: LeafNum) => PageNumString} displayPageNumberFn
|
27
|
+
* @param {string} preTag
|
28
|
+
* @param {string} postTag
|
29
|
+
*/
|
30
|
+
export function marshallSearchResults(results, displayPageNumberFn, preTag, postTag) {
|
31
|
+
// Attach matchIndex to a few things to make it easier to identify
|
32
|
+
// an active/selected match
|
33
|
+
for (const [index, match] of results.matches.entries()) {
|
34
|
+
match.matchIndex = index;
|
35
|
+
match.displayPageNumber = displayPageNumberFn(match.par[0].page);
|
36
|
+
match.html = renderMatch(match.text, preTag, postTag);
|
37
|
+
for (const par of match.par) {
|
38
|
+
for (const box of par.boxes) {
|
39
|
+
box.matchIndex = index;
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
@@ -9,11 +9,6 @@ class SearchView {
|
|
9
9
|
*/
|
10
10
|
constructor({ br, searchCancelledCallback = () => {} }) {
|
11
11
|
this.br = br;
|
12
|
-
|
13
|
-
// Search results are returned as a text blob with the hits wrapped in
|
14
|
-
// triple mustaches. Hits occasionally include text beyond the search
|
15
|
-
// term, so everything within the staches is captured and wrapped.
|
16
|
-
this.matcher = new RegExp('{{{(.+?)}}}', 'g');
|
17
12
|
this.matches = [];
|
18
13
|
this.cacheDOMElements();
|
19
14
|
this.bindEvents();
|
@@ -142,17 +137,19 @@ class SearchView {
|
|
142
137
|
const start = pool.slice(0, pool.length / 2);
|
143
138
|
const end = pool.slice(pool.length / 2);
|
144
139
|
return closestTo((comparisonFn(start, end, comparator) ? start : end), comparator);
|
145
|
-
}
|
140
|
+
};
|
146
141
|
|
147
142
|
const closestPage = closestTo(matchPages, currentPage);
|
148
143
|
return this.matches.indexOf(this.matches.find((m) => m.par[0].page === closestPage));
|
149
144
|
}
|
150
145
|
|
151
146
|
updateResultsPosition() {
|
147
|
+
if (!this.dom.searchNavigation) return;
|
152
148
|
this.dom.searchNavigation.find('[data-id=resultsCount]').text(this.resultsPosition());
|
153
149
|
}
|
154
150
|
|
155
151
|
updateSearchNavigationButtons() {
|
152
|
+
if (!this.dom.searchNavigation) return;
|
156
153
|
this.dom.searchNavigation.find('.prev').attr('disabled', !this.currentMatchIndex);
|
157
154
|
this.dom.searchNavigation.find('.next').attr('disabled', this.currentMatchIndex + 1 === this.matches.length);
|
158
155
|
}
|
@@ -226,25 +223,20 @@ class SearchView {
|
|
226
223
|
*/
|
227
224
|
renderPins(matches) {
|
228
225
|
matches.forEach((match) => {
|
229
|
-
const
|
230
|
-
const pageIndex = this.br.leafNumToIndex(match.par[0].page);
|
231
|
-
const pageNumber = this.br.getPageNum(pageIndex);
|
226
|
+
const pageIndex = this.br.book.leafNumToIndex(match.par[0].page);
|
232
227
|
const uiStringSearch = "Search result"; // i18n
|
233
|
-
const
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
.replace(this.matcher, '<b>$1</b>')
|
245
|
-
+ '...';
|
228
|
+
const percentThrough = this.br.constructor.util.cssPercentage(pageIndex, this.br.book.getNumLeafs() - 1);
|
229
|
+
|
230
|
+
let html = match.html;
|
231
|
+
if (html.length > 200) {
|
232
|
+
const start = Math.max(0, html.indexOf('<mark>') - 100);
|
233
|
+
if (start != 0) {
|
234
|
+
html = '…' + match.html
|
235
|
+
.substring(start)
|
236
|
+
// Make sure at word boundary though
|
237
|
+
.replace(/^\S+/, '');
|
238
|
+
}
|
246
239
|
}
|
247
|
-
|
248
240
|
// draw marker
|
249
241
|
$('<div>')
|
250
242
|
.addClass('BRsearch')
|
@@ -254,35 +246,27 @@ class SearchView {
|
|
254
246
|
.attr('title', uiStringSearch)
|
255
247
|
.append(`
|
256
248
|
<div class="BRquery">
|
257
|
-
<
|
258
|
-
<
|
249
|
+
<main>${html}</main>
|
250
|
+
<footer>Page ${match.displayPageNumber}</footer>
|
259
251
|
</div>
|
260
252
|
`)
|
261
|
-
.data({ pageIndex })
|
262
253
|
.appendTo(this.br.$('.BRnavline'))
|
263
|
-
.
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
.click(function (event) {
|
280
|
-
// closures are nested and deep, using an arrow function breaks references.
|
281
|
-
// Todo: update to arrow function & clean up closures
|
282
|
-
// to remove `bind` dependency
|
283
|
-
this.br._searchPluginGoToResult(+$(event.target).data('pageIndex'));
|
284
|
-
this.br.updateSearchHilites();
|
285
|
-
}.bind(this));
|
254
|
+
.on("mouseenter", (event) => {
|
255
|
+
// remove from other markers then turn on just for this
|
256
|
+
// XXX should be done when nav slider moves
|
257
|
+
const marker = event.currentTarget;
|
258
|
+
const tooltip = marker.querySelector('.BRquery');
|
259
|
+
const tooltipOffset = tooltip.getBoundingClientRect();
|
260
|
+
const targetOffset = marker.getBoundingClientRect();
|
261
|
+
const boxSizeAdjust = parseInt(getComputedStyle(tooltip).paddingLeft) * 2;
|
262
|
+
if (tooltipOffset.x - boxSizeAdjust < 0) {
|
263
|
+
tooltip.style.setProperty('transform', `translateX(-${targetOffset.left - boxSizeAdjust}px)`);
|
264
|
+
}
|
265
|
+
$('.BRsearch,.BRchapter').removeClass('front');
|
266
|
+
$(event.target).addClass('front');
|
267
|
+
})
|
268
|
+
.on("mouseleave", (event) => $(event.target).removeClass('front'))
|
269
|
+
.on("click", () => { this.br._searchPluginGoToResult(match.matchIndex); });
|
286
270
|
});
|
287
271
|
}
|
288
272
|
|
@@ -386,14 +370,6 @@ class SearchView {
|
|
386
370
|
}
|
387
371
|
}
|
388
372
|
|
389
|
-
/**
|
390
|
-
* @param {Event} e
|
391
|
-
*/
|
392
|
-
handleNavToggledCallback(e) {
|
393
|
-
const is_visible = this.br.navigationIsVisible();
|
394
|
-
this.togglePinsFor(is_visible);
|
395
|
-
}
|
396
|
-
|
397
373
|
handleSearchStarted() {
|
398
374
|
this.emptyMatches();
|
399
375
|
this.br.removeSearchHilites();
|
@@ -428,7 +404,6 @@ class SearchView {
|
|
428
404
|
|
429
405
|
window.addEventListener(`${namespace}SearchCallbackError`, this.handleSearchCallbackError.bind(this));
|
430
406
|
$(document).on(`${namespace}SearchCallback`, this.handleSearchCallback.bind(this))
|
431
|
-
.on(`${namespace}navToggled`, this.handleNavToggledCallback.bind(this))
|
432
407
|
.on(`${namespace}SearchStarted`, this.handleSearchStarted.bind(this))
|
433
408
|
.on(`${namespace}SearchCallbackBookNotIndexed`, this.handleSearchCallbackBookNotIndexed.bind(this))
|
434
409
|
.on(`${namespace}SearchCallbackEmpty`, this.handleSearchCallbackEmpty.bind(this))
|