@internetarchive/bookreader 5.0.0-88-alpha.7 → 5.0.0-88-alpha.9
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/babel.config.js +30 -12
- package/dist/esm/BookNavigator/assets/bookmark-colors.js +4 -0
- package/dist/esm/BookNavigator/assets/button-base.js +4 -0
- package/dist/esm/BookNavigator/assets/ia-logo.js +4 -0
- package/dist/esm/BookNavigator/assets/icon_checkmark.js +8 -0
- package/dist/esm/BookNavigator/assets/icon_close.js +4 -0
- package/dist/esm/BookNavigator/book-navigator.js +612 -0
- package/dist/esm/BookNavigator/bookmarks/bookmark-button.js +35 -0
- package/dist/esm/BookNavigator/bookmarks/bookmark-edit.js +78 -0
- package/dist/esm/BookNavigator/bookmarks/bookmarks-list.js +160 -0
- package/dist/esm/BookNavigator/bookmarks/bookmarks-loginCTA.js +24 -0
- package/dist/esm/BookNavigator/bookmarks/bookmarks-provider.js +55 -0
- package/dist/esm/BookNavigator/bookmarks/ia-bookmarks.js +521 -0
- package/dist/esm/BookNavigator/delete-modal-actions.js +29 -0
- package/dist/esm/BookNavigator/downloads/downloads-provider.js +84 -0
- package/dist/esm/BookNavigator/downloads/downloads.js +69 -0
- package/dist/esm/BookNavigator/search/search-provider.js +238 -0
- package/dist/esm/BookNavigator/search/search-results.js +161 -0
- package/dist/esm/BookNavigator/sharing.js +26 -0
- package/dist/esm/BookNavigator/viewable-files.js +94 -0
- package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments-provider.js +83 -0
- package/dist/esm/BookNavigator/visual-adjustments/visual-adjustments.js +131 -0
- package/dist/esm/BookReader/BookModel.js +575 -0
- package/dist/esm/BookReader/DragScrollable.js +224 -0
- package/dist/esm/BookReader/ImageCache.js +122 -0
- package/dist/esm/BookReader/Mode1Up.js +114 -0
- package/dist/esm/BookReader/Mode1UpLit.js +579 -0
- package/dist/esm/BookReader/Mode2Up.js +106 -0
- package/dist/esm/BookReader/Mode2UpLit.js +1020 -0
- package/dist/esm/BookReader/ModeCoordinateSpace.js +28 -0
- package/dist/esm/BookReader/ModeSmoothZoom.js +318 -0
- package/dist/esm/BookReader/ModeThumb.js +366 -0
- package/dist/esm/BookReader/Navbar/Navbar.js +253 -0
- package/dist/esm/BookReader/PageContainer.js +165 -0
- package/dist/esm/BookReader/ReduceSet.js +27 -0
- package/dist/esm/BookReader/Toolbar/Toolbar.js +242 -0
- package/dist/esm/BookReader/events.js +20 -0
- package/dist/esm/BookReader/options.js +331 -0
- package/dist/esm/BookReader/utils/HTMLDimensionsCacher.js +48 -0
- package/dist/esm/BookReader/utils/ScrollClassAdder.js +31 -0
- package/dist/esm/BookReader/utils/SelectionObserver.js +42 -0
- package/dist/esm/BookReader/utils/classes.js +37 -0
- package/dist/esm/BookReader/utils.js +315 -0
- package/dist/esm/BookReader.js +1827 -0
- package/dist/esm/assets/icons/1up.svg +12 -0
- package/dist/esm/assets/icons/2up.svg +15 -0
- package/dist/esm/assets/icons/advance.svg +26 -0
- package/dist/esm/assets/icons/chevron-right.svg +1 -0
- package/dist/esm/assets/icons/close-circle-dark.svg +1 -0
- package/dist/esm/assets/icons/close-circle.svg +1 -0
- package/dist/esm/assets/icons/fullscreen.svg +17 -0
- package/dist/esm/assets/icons/fullscreen_exit.svg +17 -0
- package/dist/esm/assets/icons/hamburger.svg +15 -0
- package/dist/esm/assets/icons/left-arrow.svg +12 -0
- package/dist/esm/assets/icons/magnify-minus.svg +12 -0
- package/dist/esm/assets/icons/magnify-plus.svg +13 -0
- package/dist/esm/assets/icons/magnify.svg +15 -0
- package/dist/esm/assets/icons/pause.svg +23 -0
- package/dist/esm/assets/icons/play.svg +22 -0
- package/dist/esm/assets/icons/playback-speed.svg +34 -0
- package/dist/esm/assets/icons/read-aloud.svg +22 -0
- package/dist/esm/assets/icons/review.svg +22 -0
- package/dist/esm/assets/icons/thumbnails.svg +17 -0
- package/dist/esm/assets/icons/voice.svg +1 -0
- package/dist/esm/assets/icons/volume-full.svg +22 -0
- package/dist/esm/assets/images/BRicons.png +0 -0
- package/dist/esm/assets/images/BRicons.svg +94 -0
- package/dist/esm/assets/images/BRicons_ia.png +0 -0
- package/dist/esm/assets/images/back_pages.png +0 -0
- package/dist/esm/assets/images/book_bottom_icon.png +0 -0
- package/dist/esm/assets/images/book_down_icon.png +0 -0
- package/dist/esm/assets/images/book_left_icon.png +0 -0
- package/dist/esm/assets/images/book_leftmost_icon.png +0 -0
- package/dist/esm/assets/images/book_right_icon.png +0 -0
- package/dist/esm/assets/images/book_rightmost_icon.png +0 -0
- package/dist/esm/assets/images/book_top_icon.png +0 -0
- package/dist/esm/assets/images/book_up_icon.png +0 -0
- package/dist/esm/assets/images/books_graphic.svg +177 -0
- package/dist/esm/assets/images/booksplit.png +0 -0
- package/dist/esm/assets/images/control_pause_icon.png +0 -0
- package/dist/esm/assets/images/control_play_icon.png +0 -0
- package/dist/esm/assets/images/embed_icon.png +0 -0
- package/dist/esm/assets/images/icon-home-ia.png +0 -0
- package/dist/esm/assets/images/icon_OL-logo-xs.png +0 -0
- package/dist/esm/assets/images/icon_alert-xs.png +0 -0
- package/dist/esm/assets/images/icon_book.svg +12 -0
- package/dist/esm/assets/images/icon_bookmark.svg +12 -0
- package/dist/esm/assets/images/icon_close-pop.png +0 -0
- package/dist/esm/assets/images/icon_download.png +0 -0
- package/dist/esm/assets/images/icon_gear.svg +14 -0
- package/dist/esm/assets/images/icon_hamburger.svg +20 -0
- package/dist/esm/assets/images/icon_home.png +0 -0
- package/dist/esm/assets/images/icon_home.svg +21 -0
- package/dist/esm/assets/images/icon_home_ia.png +0 -0
- package/dist/esm/assets/images/icon_indicator.png +0 -0
- package/dist/esm/assets/images/icon_info.svg +11 -0
- package/dist/esm/assets/images/icon_one_page.svg +8 -0
- package/dist/esm/assets/images/icon_pause.svg +1 -0
- package/dist/esm/assets/images/icon_play.svg +1 -0
- package/dist/esm/assets/images/icon_playback-rate.svg +15 -0
- package/dist/esm/assets/images/icon_return.png +0 -0
- package/dist/esm/assets/images/icon_search_button.svg +8 -0
- package/dist/esm/assets/images/icon_share.svg +9 -0
- package/dist/esm/assets/images/icon_skip-ahead.svg +6 -0
- package/dist/esm/assets/images/icon_skip-back.svg +13 -0
- package/dist/esm/assets/images/icon_speaker.svg +18 -0
- package/dist/esm/assets/images/icon_speaker_open.svg +10 -0
- package/dist/esm/assets/images/icon_thumbnails.svg +12 -0
- package/dist/esm/assets/images/icon_toc.svg +5 -0
- package/dist/esm/assets/images/icon_two_pages.svg +9 -0
- package/dist/esm/assets/images/icon_zoomer.png +0 -0
- package/dist/esm/assets/images/loading.gif +0 -0
- package/dist/esm/assets/images/logo_icon.png +0 -0
- package/dist/esm/assets/images/marker_chap-off.png +0 -0
- package/dist/esm/assets/images/marker_chap-off.svg +11 -0
- package/dist/esm/assets/images/marker_chap-off_ia.png +0 -0
- package/dist/esm/assets/images/marker_chap-on.png +0 -0
- package/dist/esm/assets/images/marker_chap-on.svg +11 -0
- package/dist/esm/assets/images/marker_srch-on.svg +11 -0
- package/dist/esm/assets/images/marker_srchchap-off.png +0 -0
- package/dist/esm/assets/images/marker_srchchap-on.png +0 -0
- package/dist/esm/assets/images/nav_control-dn.png +0 -0
- package/dist/esm/assets/images/nav_control-dn_ia.png +0 -0
- package/dist/esm/assets/images/nav_control-up.png +0 -0
- package/dist/esm/assets/images/nav_control-up_ia.png +0 -0
- package/dist/esm/assets/images/nav_control.png +0 -0
- package/dist/esm/assets/images/one_page_mode_icon.png +0 -0
- package/dist/esm/assets/images/paper-badge.png +0 -0
- package/dist/esm/assets/images/print_icon.png +0 -0
- package/dist/esm/assets/images/progressbar.gif +0 -0
- package/dist/esm/assets/images/right_edges.png +0 -0
- package/dist/esm/assets/images/slider.png +0 -0
- package/dist/esm/assets/images/slider_ia.png +0 -0
- package/dist/esm/assets/images/thumbnail_mode_icon.png +0 -0
- package/dist/esm/assets/images/transparent.png +0 -0
- package/dist/esm/assets/images/two_page_mode_icon.png +0 -0
- package/dist/esm/assets/images/unviewable_page.png +0 -0
- package/dist/esm/assets/images/zoom_in_icon.png +0 -0
- package/dist/esm/assets/images/zoom_out_icon.png +0 -0
- package/dist/esm/css/BookReader.scss +85 -0
- package/dist/esm/css/_BRBookmarks.scss +29 -0
- package/dist/esm/css/_BRComponent.scss +13 -0
- package/dist/esm/css/_BRfloat.scss +197 -0
- package/dist/esm/css/_BRicon.scss +54 -0
- package/dist/esm/css/_BRmain.scss +262 -0
- package/dist/esm/css/_BRnav.scss +354 -0
- package/dist/esm/css/_BRpages.scss +213 -0
- package/dist/esm/css/_BRsearch.scss +268 -0
- package/dist/esm/css/_BRtoolbar.scss +84 -0
- package/dist/esm/css/_BRvendor.scss +5 -0
- package/dist/esm/css/_TextSelection.scss +108 -0
- package/dist/esm/css/_colorbox.scss +52 -0
- package/dist/esm/css/_controls.scss +257 -0
- package/dist/esm/css/_icons.scss +121 -0
- package/dist/esm/ia-bookreader/ia-bookreader.js +141 -0
- package/dist/esm/jquery-wrapper.js +3 -0
- package/dist/esm/plugins/plugin.archive_analytics.js +72 -0
- package/dist/esm/plugins/plugin.autoplay.js +119 -0
- package/dist/esm/plugins/plugin.chapters.js +288 -0
- package/dist/esm/plugins/plugin.iframe.js +44 -0
- package/dist/esm/plugins/plugin.iiif.js +146 -0
- package/dist/esm/plugins/plugin.resume.js +66 -0
- package/dist/esm/plugins/plugin.text_selection.js +621 -0
- package/dist/esm/plugins/plugin.vendor-fullscreen.js +227 -0
- package/dist/esm/plugins/search/plugin.search.js +499 -0
- package/dist/esm/plugins/search/utils.js +42 -0
- package/dist/esm/plugins/search/view.js +360 -0
- package/dist/esm/plugins/tts/AbstractTTSEngine.js +282 -0
- package/dist/esm/plugins/tts/FestivalTTSEngine.js +192 -0
- package/dist/esm/plugins/tts/PageChunk.js +105 -0
- package/dist/esm/plugins/tts/PageChunkIterator.js +155 -0
- package/dist/esm/plugins/tts/WebTTSEngine.js +364 -0
- package/dist/esm/plugins/tts/plugin.tts.js +315 -0
- package/dist/esm/plugins/tts/tooltip_dict.js +14 -0
- package/dist/esm/plugins/tts/utils.js +79 -0
- package/dist/esm/plugins/url/UrlPlugin.js +197 -0
- package/dist/esm/plugins/url/plugin.url.js +212 -0
- package/dist/esm/util/browserSniffing.js +56 -0
- package/dist/esm/util/debouncer.js +25 -0
- package/dist/esm/util/docCookies.js +75 -0
- package/dist/esm/util/strings.js +34 -0
- package/jsconfig.json +1 -0
- package/package.json +13 -6
@@ -0,0 +1,499 @@
|
|
1
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
2
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
3
|
+
// @ts-check
|
4
|
+
/* global BookReader */
|
5
|
+
/**
|
6
|
+
* Plugin for Archive.org book search
|
7
|
+
* Events fired at various points throughout search processing are published
|
8
|
+
* on the document DOM element. These can be subscribed to using jQuery's event
|
9
|
+
* binding method `$.fn.on`. All of the events are prefixed with a BookReader
|
10
|
+
* namespace. The events are:
|
11
|
+
*
|
12
|
+
* @event BookReader:SearchStarted - When a search form is submitted, immediately
|
13
|
+
* before an AJAX call is made to request search results
|
14
|
+
* @event BookReader:SearchCallback - When the search AJAX call is returned and at
|
15
|
+
* least one result is returned. The event callback receives an object
|
16
|
+
* with the `results`, plugin `options`, and the BookReader `instance`
|
17
|
+
* @event BookReader:SearchCallbackError - When the AJAX request returns an error.
|
18
|
+
* Receives the `results` and `instance`
|
19
|
+
* @event BookReader:SearchCallbackNotIndexed - When a message is received that
|
20
|
+
* the book has not had OCR text indexed yet. Receives `instance`
|
21
|
+
* @event BookReader:SearchCallbackEmpty - When no results found. Receives
|
22
|
+
* `instance`
|
23
|
+
* @event BookReader:SearchCanceled - When no results found. Receives
|
24
|
+
* `instance`
|
25
|
+
*/
|
26
|
+
import { poll } from '../../BookReader/utils.js';
|
27
|
+
import { renderBoxesInPageContainerLayer } from '../../BookReader/PageContainer.js';
|
28
|
+
import SearchView from './view.js';
|
29
|
+
import { marshallSearchResults } from './utils.js';
|
30
|
+
/** @typedef {import('../../BookReader/PageContainer').PageContainer} PageContainer */
|
31
|
+
/** @typedef {import('../../BookReader/BookModel').PageIndex} PageIndex */
|
32
|
+
/** @typedef {import('../../BookReader/BookModel').LeafNum} LeafNum */
|
33
|
+
/** @typedef {import('../../BookReader/BookModel').PageNumString} PageNumString */
|
34
|
+
|
35
|
+
jQuery.extend(BookReader.defaultOptions, {
|
36
|
+
server: 'ia600609.us.archive.org',
|
37
|
+
bookId: '',
|
38
|
+
subPrefix: '',
|
39
|
+
bookPath: '',
|
40
|
+
enableSearch: true,
|
41
|
+
searchInsideProtocol: 'https',
|
42
|
+
searchInsideUrl: '/fulltext/inside.php',
|
43
|
+
searchInsidePreTag: '{{{',
|
44
|
+
searchInsidePostTag: '}}}',
|
45
|
+
initialSearchTerm: null
|
46
|
+
});
|
47
|
+
|
48
|
+
/** @override */
|
49
|
+
BookReader.prototype.setup = function (super_) {
|
50
|
+
return function (options) {
|
51
|
+
super_.call(this, options);
|
52
|
+
this.searchTerm = '';
|
53
|
+
this.searchResults = null;
|
54
|
+
this.searchInsideUrl = options.searchInsideUrl;
|
55
|
+
this.enableSearch = options.enableSearch;
|
56
|
+
|
57
|
+
// Base server used by some api calls
|
58
|
+
this.bookId = options.bookId;
|
59
|
+
this.server = options.server;
|
60
|
+
this.subPrefix = options.subPrefix;
|
61
|
+
this.bookPath = options.bookPath;
|
62
|
+
this.searchXHR = null;
|
63
|
+
this._cancelSearch.bind(this);
|
64
|
+
this.cancelSearchRequest.bind(this);
|
65
|
+
|
66
|
+
/** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
|
67
|
+
this._searchBoxesByIndex = {};
|
68
|
+
if (this.enableSearch) {
|
69
|
+
this.searchView = new SearchView({
|
70
|
+
br: this,
|
71
|
+
searchCancelledCallback: () => {
|
72
|
+
this._cancelSearch();
|
73
|
+
this.trigger('SearchCanceled', {
|
74
|
+
term: this.searchTerm,
|
75
|
+
instance: this
|
76
|
+
});
|
77
|
+
}
|
78
|
+
});
|
79
|
+
} else {
|
80
|
+
this.searchView = null;
|
81
|
+
}
|
82
|
+
};
|
83
|
+
}(BookReader.prototype.setup);
|
84
|
+
|
85
|
+
/** @override */
|
86
|
+
BookReader.prototype.init = function (super_) {
|
87
|
+
return function () {
|
88
|
+
super_.call(this);
|
89
|
+
if (!this.enableSearch) return;
|
90
|
+
this.searchView.init();
|
91
|
+
if (this.options.initialSearchTerm) {
|
92
|
+
/**
|
93
|
+
* this.search() take two parameter
|
94
|
+
* 1. this.options.initialSearchTerm - search term
|
95
|
+
* 2. {
|
96
|
+
* goToFirstResult: this.options.goToFirstResult,
|
97
|
+
* suppressFragmentChange: false // always want to change fragment in URL
|
98
|
+
* }
|
99
|
+
*/
|
100
|
+
this.search(this.options.initialSearchTerm, {
|
101
|
+
goToFirstResult: this.options.goToFirstResult,
|
102
|
+
suppressFragmentChange: false
|
103
|
+
});
|
104
|
+
}
|
105
|
+
};
|
106
|
+
}(BookReader.prototype.init);
|
107
|
+
|
108
|
+
/** @override */
|
109
|
+
BookReader.prototype.buildToolbarElement = function (super_) {
|
110
|
+
return function () {
|
111
|
+
var $el = super_.call(this);
|
112
|
+
if (!this.enableSearch) {
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
if (this.searchView.dom.toolbarSearch) {
|
116
|
+
$el.find('.BRtoolbarSectionInfo').after(this.searchView.dom.toolbarSearch);
|
117
|
+
}
|
118
|
+
return $el;
|
119
|
+
};
|
120
|
+
}(BookReader.prototype.buildToolbarElement);
|
121
|
+
|
122
|
+
/** @override */
|
123
|
+
BookReader.prototype._createPageContainer = function (super_) {
|
124
|
+
return function (index) {
|
125
|
+
var pageContainer = super_.call(this, index);
|
126
|
+
if (this.enableSearch && pageContainer.page && index in this._searchBoxesByIndex) {
|
127
|
+
var pageIndex = pageContainer.page.index;
|
128
|
+
var boxes = this._searchBoxesByIndex[pageIndex];
|
129
|
+
renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, pageContainer.page, pageContainer.$container[0], boxes.map(b => "match-index-".concat(b.matchIndex)));
|
130
|
+
}
|
131
|
+
return pageContainer;
|
132
|
+
};
|
133
|
+
}(BookReader.prototype._createPageContainer);
|
134
|
+
|
135
|
+
/**
|
136
|
+
* @typedef {object} SearchOptions
|
137
|
+
* @property {boolean} goToFirstResult
|
138
|
+
* @property {boolean} disablePopup
|
139
|
+
* @property {(null|function)} error - @deprecated at v.5.0
|
140
|
+
* @property {(null|function)} success - @deprecated at v.5.0
|
141
|
+
*/
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Submits search request
|
145
|
+
*
|
146
|
+
* @param {string} term
|
147
|
+
* @param {SearchOptions} overrides
|
148
|
+
*/
|
149
|
+
BookReader.prototype.search = /*#__PURE__*/_asyncToGenerator(function* () {
|
150
|
+
var term = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
151
|
+
var overrides = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
152
|
+
/** @type {SearchOptions} */
|
153
|
+
var defaultOptions = {
|
154
|
+
goToFirstResult: false,
|
155
|
+
/* jump to the first result (default=false) */
|
156
|
+
disablePopup: false,
|
157
|
+
/* don't show the modal progress (default=false) */
|
158
|
+
suppressFragmentChange: false,
|
159
|
+
/* don't change the URL on initial load */
|
160
|
+
error: null,
|
161
|
+
/* optional error handler (default=null) */
|
162
|
+
success: null /* optional success handler (default=null) */
|
163
|
+
};
|
164
|
+
var options = jQuery.extend({}, defaultOptions, overrides);
|
165
|
+
this.suppressFragmentChange = options.suppressFragmentChange;
|
166
|
+
this.searchCancelled = false;
|
167
|
+
|
168
|
+
// strip slashes, since this goes in the url
|
169
|
+
this.searchTerm = term.replace(/\//g, ' ');
|
170
|
+
if (!options.suppressFragmentChange) {
|
171
|
+
this.trigger(BookReader.eventNames.fragmentChange);
|
172
|
+
}
|
173
|
+
|
174
|
+
// Add quotes to the term. This is to compenstate for the backends default OR query
|
175
|
+
// term = term.replace(/['"]+/g, '');
|
176
|
+
// term = '"' + term + '"';
|
177
|
+
|
178
|
+
// Remove the port and userdir
|
179
|
+
var serverPath = this.server.replace(/:.+/, '');
|
180
|
+
var baseUrl = "".concat(this.options.searchInsideProtocol, "://").concat(serverPath).concat(this.searchInsideUrl, "?");
|
181
|
+
|
182
|
+
// Remove subPrefix from end of path
|
183
|
+
var path = this.bookPath;
|
184
|
+
var subPrefixWithSlash = "/".concat(this.subPrefix);
|
185
|
+
if (this.bookPath.length - this.bookPath.lastIndexOf(subPrefixWithSlash) == subPrefixWithSlash.length) {
|
186
|
+
path = this.bookPath.substr(0, this.bookPath.length - subPrefixWithSlash.length);
|
187
|
+
}
|
188
|
+
var urlParams = {
|
189
|
+
item_id: this.bookId,
|
190
|
+
doc: this.subPrefix,
|
191
|
+
path,
|
192
|
+
q: term,
|
193
|
+
pre_tag: this.options.searchInsidePreTag,
|
194
|
+
post_tag: this.options.searchInsidePostTag
|
195
|
+
};
|
196
|
+
|
197
|
+
// NOTE that the API does not expect / (slashes) to be encoded. (%2F) won't work
|
198
|
+
var paramStr = $.param(urlParams).replace(/%2F/g, '/');
|
199
|
+
var url = "".concat(baseUrl).concat(paramStr);
|
200
|
+
var callSearchResultsCallback = searchInsideResults => {
|
201
|
+
if (this.searchCancelled) {
|
202
|
+
return;
|
203
|
+
}
|
204
|
+
var responseHasError = searchInsideResults.error || !searchInsideResults.matches.length;
|
205
|
+
var hasCustomError = typeof options.error === 'function';
|
206
|
+
var hasCustomSuccess = typeof options.success === 'function';
|
207
|
+
if (responseHasError) {
|
208
|
+
console.error('Search Inside Response Error', searchInsideResults.error || 'matches.length == 0');
|
209
|
+
hasCustomError ? options.error.call(this, searchInsideResults, options) : this.BRSearchCallbackError(searchInsideResults, options);
|
210
|
+
} else {
|
211
|
+
hasCustomSuccess ? options.success.call(this, searchInsideResults, options) : this.BRSearchCallback(searchInsideResults, options);
|
212
|
+
}
|
213
|
+
};
|
214
|
+
this.trigger('SearchStarted', {
|
215
|
+
term: this.searchTerm,
|
216
|
+
instance: this
|
217
|
+
});
|
218
|
+
callSearchResultsCallback(yield $.ajax({
|
219
|
+
url: url,
|
220
|
+
cache: true,
|
221
|
+
xhrFields: {
|
222
|
+
withCredentials: this.protected
|
223
|
+
},
|
224
|
+
beforeSend: xhr => {
|
225
|
+
this.searchXHR = xhr;
|
226
|
+
}
|
227
|
+
}));
|
228
|
+
});
|
229
|
+
|
230
|
+
/**
|
231
|
+
* cancels AJAX Call
|
232
|
+
* emits custom event
|
233
|
+
*/
|
234
|
+
BookReader.prototype._cancelSearch = function () {
|
235
|
+
var _this$searchXHR;
|
236
|
+
(_this$searchXHR = this.searchXHR) === null || _this$searchXHR === void 0 || _this$searchXHR.abort();
|
237
|
+
this.searchView.clearSearchFieldAndResults(false);
|
238
|
+
this.searchTerm = '';
|
239
|
+
this.searchXHR = null;
|
240
|
+
this.searchCancelled = true;
|
241
|
+
this.searchResults = [];
|
242
|
+
};
|
243
|
+
|
244
|
+
/**
|
245
|
+
* External function to cancel search
|
246
|
+
* checks for term & xhr in flight before running
|
247
|
+
*/
|
248
|
+
BookReader.prototype.cancelSearchRequest = function () {
|
249
|
+
this.searchCancelled = true;
|
250
|
+
if (this.searchXHR !== null) {
|
251
|
+
this._cancelSearch();
|
252
|
+
this.searchView.toggleSearchPending();
|
253
|
+
this.trigger('SearchCanceled', {
|
254
|
+
term: this.searchTerm,
|
255
|
+
instance: this
|
256
|
+
});
|
257
|
+
}
|
258
|
+
};
|
259
|
+
|
260
|
+
/**
|
261
|
+
* @typedef {object} SearchInsideMatchBox
|
262
|
+
* @property {number} page
|
263
|
+
* @property {number} r
|
264
|
+
* @property {number} l
|
265
|
+
* @property {number} b
|
266
|
+
* @property {number} t
|
267
|
+
* @property {HTMLDivElement} [div]
|
268
|
+
* @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.
|
269
|
+
*/
|
270
|
+
|
271
|
+
/**
|
272
|
+
* @typedef {object} SearchInsideMatch
|
273
|
+
* @property {number} matchIndex This is a fake field! Not part of the API response. It is added by the JS.
|
274
|
+
* @property {string} displayPageNumber (fake field) The page number as it should be displayed in the UI.
|
275
|
+
* @property {string} html (computed field) The html-escaped raw html to display in the UI.
|
276
|
+
* @property {string} text
|
277
|
+
* @property {Array<{ page: number, boxes: SearchInsideMatchBox[] }>} par
|
278
|
+
*/
|
279
|
+
|
280
|
+
/**
|
281
|
+
* @typedef {object} SearchInsideResults
|
282
|
+
* @property {string} error
|
283
|
+
* @property {SearchInsideMatch[]} matches
|
284
|
+
* @property {boolean} indexed
|
285
|
+
*/
|
286
|
+
|
287
|
+
/**
|
288
|
+
* Search Results return handler
|
289
|
+
* @param {SearchInsideResults} results
|
290
|
+
* @param {object} options
|
291
|
+
* @param {boolean} options.goToFirstResult
|
292
|
+
*/
|
293
|
+
BookReader.prototype.BRSearchCallback = function (results, options) {
|
294
|
+
marshallSearchResults(results, pageNum => this.book.getPageNum(this.book.leafNumToIndex(pageNum)), this.options.searchInsidePreTag, this.options.searchInsidePostTag);
|
295
|
+
this.searchResults = results || [];
|
296
|
+
this.updateSearchHilites();
|
297
|
+
this.removeProgressPopup();
|
298
|
+
if (options.goToFirstResult) {
|
299
|
+
this._searchPluginGoToResult(0);
|
300
|
+
}
|
301
|
+
this.trigger('SearchCallback', {
|
302
|
+
results,
|
303
|
+
options,
|
304
|
+
instance: this
|
305
|
+
});
|
306
|
+
};
|
307
|
+
|
308
|
+
/**
|
309
|
+
* Main search results error handler
|
310
|
+
* @callback
|
311
|
+
* @param {SearchInsideResults} results
|
312
|
+
*/
|
313
|
+
BookReader.prototype.BRSearchCallbackError = function (results) {
|
314
|
+
this._BRSearchCallbackError(results);
|
315
|
+
};
|
316
|
+
|
317
|
+
/**
|
318
|
+
* @private draws search results error
|
319
|
+
* @callback
|
320
|
+
* @param {SearchInsideResults} results
|
321
|
+
* @param {jQuery} $el
|
322
|
+
* @param {boolean} fade
|
323
|
+
*/
|
324
|
+
BookReader.prototype._BRSearchCallbackError = function (results) {
|
325
|
+
this.searchResults = results;
|
326
|
+
var basePayload = {
|
327
|
+
term: this.searchTerm,
|
328
|
+
instance: this
|
329
|
+
};
|
330
|
+
if (results.error) {
|
331
|
+
var payload = Object.assign({}, basePayload, {
|
332
|
+
results
|
333
|
+
});
|
334
|
+
this.trigger('SearchCallbackError', payload);
|
335
|
+
} else if (0 == results.matches.length) {
|
336
|
+
if (false === results.indexed) {
|
337
|
+
this.trigger('SearchCallbackBookNotIndexed', basePayload);
|
338
|
+
return;
|
339
|
+
}
|
340
|
+
this.trigger('SearchCallbackEmpty', basePayload);
|
341
|
+
}
|
342
|
+
};
|
343
|
+
|
344
|
+
/**
|
345
|
+
* updates search on-page highlights controller
|
346
|
+
*/
|
347
|
+
BookReader.prototype.updateSearchHilites = function () {
|
348
|
+
var _this$searchResults;
|
349
|
+
/** @type {SearchInsideMatch[]} */
|
350
|
+
var matches = ((_this$searchResults = this.searchResults) === null || _this$searchResults === void 0 ? void 0 : _this$searchResults.matches) || [];
|
351
|
+
/** @type { {[pageIndex: number]: SearchInsideMatchBox[]} } */
|
352
|
+
var boxesByIndex = {};
|
353
|
+
|
354
|
+
// Clear any existing svg layers
|
355
|
+
this.removeSearchHilites();
|
356
|
+
|
357
|
+
// Group by pageIndex
|
358
|
+
for (var match of matches) {
|
359
|
+
for (var box of match.par[0].boxes) {
|
360
|
+
var pageIndex = this.book.leafNumToIndex(box.page);
|
361
|
+
var pageBoxes = boxesByIndex[pageIndex] || (boxesByIndex[pageIndex] = []);
|
362
|
+
pageBoxes.push(box);
|
363
|
+
}
|
364
|
+
}
|
365
|
+
|
366
|
+
// update any already created pages
|
367
|
+
for (var [pageIndexString, boxes] of Object.entries(boxesByIndex)) {
|
368
|
+
var _pageIndex = parseFloat(pageIndexString);
|
369
|
+
var page = this.book.getPage(_pageIndex);
|
370
|
+
var pageContainers = this.getActivePageContainerElementsForIndex(_pageIndex);
|
371
|
+
for (var container of pageContainers) {
|
372
|
+
renderBoxesInPageContainerLayer('searchHiliteLayer', boxes, page, container, boxes.map(b => "match-index-".concat(b.matchIndex)));
|
373
|
+
}
|
374
|
+
}
|
375
|
+
this._searchBoxesByIndex = boxesByIndex;
|
376
|
+
};
|
377
|
+
|
378
|
+
/**
|
379
|
+
* remove search highlights
|
380
|
+
*/
|
381
|
+
BookReader.prototype.removeSearchHilites = function () {
|
382
|
+
$(this.getActivePageContainerElements()).find('.searchHiliteLayer').remove();
|
383
|
+
};
|
384
|
+
|
385
|
+
/**
|
386
|
+
* @private
|
387
|
+
* Goes to the page specified. If the page is not viewable, tries to load the page
|
388
|
+
* FIXME Most of this logic is IA specific, and should be less integrated into here
|
389
|
+
* or at least more configurable.
|
390
|
+
* @param {number} matchIndex
|
391
|
+
*/
|
392
|
+
BookReader.prototype._searchPluginGoToResult = /*#__PURE__*/function () {
|
393
|
+
var _ref2 = _asyncToGenerator(function* (matchIndex) {
|
394
|
+
var _this$searchResults2;
|
395
|
+
var match = (_this$searchResults2 = this.searchResults) === null || _this$searchResults2 === void 0 ? void 0 : _this$searchResults2.matches[matchIndex];
|
396
|
+
var book = this.book;
|
397
|
+
var pageIndex = book.leafNumToIndex(match.par[0].page);
|
398
|
+
var page = book.getPage(pageIndex);
|
399
|
+
var onNearbyPage = Math.abs(this.currentIndex() - pageIndex) < 3;
|
400
|
+
var makeUnviewableAtEnd = false;
|
401
|
+
if (!page.isViewable) {
|
402
|
+
var resp = yield fetch('/services/bookreader/request_page?' + new URLSearchParams({
|
403
|
+
id: this.options.bookId,
|
404
|
+
subprefix: this.options.subPrefix,
|
405
|
+
leafNum: page.leafNum
|
406
|
+
})).then(r => r.json());
|
407
|
+
for (var leafNum of resp.value) {
|
408
|
+
book.getPage(book.leafNumToIndex(leafNum)).makeViewable();
|
409
|
+
}
|
410
|
+
|
411
|
+
// not able to show page; make the page viewable anyways so that it can
|
412
|
+
// actually open. On IA, it has a fallback to a special error page.
|
413
|
+
if (!resp.value.length) {
|
414
|
+
book.getPage(pageIndex).makeViewable();
|
415
|
+
makeUnviewableAtEnd = true;
|
416
|
+
}
|
417
|
+
|
418
|
+
// Trigger an update of book
|
419
|
+
this._modes.mode1Up.mode1UpLit.updatePages();
|
420
|
+
if (this.activeMode == this._modes.mode1Up) {
|
421
|
+
yield this._modes.mode1Up.mode1UpLit.updateComplete;
|
422
|
+
}
|
423
|
+
}
|
424
|
+
/* this updates the URL */
|
425
|
+
if (!this._isIndexDisplayed(pageIndex)) {
|
426
|
+
this.suppressFragmentChange = false;
|
427
|
+
this.jumpToIndex(pageIndex);
|
428
|
+
}
|
429
|
+
|
430
|
+
// Reset it to unviewable if it wasn't resolved
|
431
|
+
if (makeUnviewableAtEnd) {
|
432
|
+
book.getPage(pageIndex).makeViewable(false);
|
433
|
+
}
|
434
|
+
|
435
|
+
// Scroll/flash in the ui
|
436
|
+
var $boxes = yield poll(() => $("rect.match-index-".concat(match.matchIndex)), {
|
437
|
+
until: result => result.length > 0
|
438
|
+
});
|
439
|
+
if ($boxes.length) {
|
440
|
+
$boxes.css('animation', 'none');
|
441
|
+
$boxes[0].scrollIntoView({
|
442
|
+
// Only vertically center the highlight if we're in 1up or in full screen. In
|
443
|
+
// 2up, if we're not fullscreen, the whole body gets scrolled around to try to
|
444
|
+
// center the highlight 🙄 See:
|
445
|
+
// https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move/11041376
|
446
|
+
// Note: nearest doesn't quite work great, because the ReadAloud toolbar is now
|
447
|
+
// full-width, and covers up the last line of the highlight.
|
448
|
+
block: this.constMode1up == this.mode || this.isFullscreenActive ? 'center' : 'nearest',
|
449
|
+
inline: 'center',
|
450
|
+
behavior: onNearbyPage ? 'smooth' : 'auto'
|
451
|
+
});
|
452
|
+
// wait for animation to start
|
453
|
+
yield new Promise(resolve => setTimeout(resolve, 100));
|
454
|
+
$boxes.removeAttr("style");
|
455
|
+
}
|
456
|
+
});
|
457
|
+
return function (_x) {
|
458
|
+
return _ref2.apply(this, arguments);
|
459
|
+
};
|
460
|
+
}();
|
461
|
+
|
462
|
+
/**
|
463
|
+
* Removes all search pins
|
464
|
+
*/
|
465
|
+
BookReader.prototype.removeSearchResults = function () {
|
466
|
+
var suppressFragmentChange = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
467
|
+
this.removeSearchHilites(); //be sure to set all box.divs to null
|
468
|
+
this.searchTerm = null;
|
469
|
+
this.searchResults = null;
|
470
|
+
if (!suppressFragmentChange) {
|
471
|
+
this.trigger(BookReader.eventNames.fragmentChange);
|
472
|
+
}
|
473
|
+
};
|
474
|
+
|
475
|
+
/**
|
476
|
+
* Returns true if a search highlight is currently being displayed
|
477
|
+
* @returns {boolean}
|
478
|
+
*/
|
479
|
+
BookReader.prototype.searchHighlightVisible = function () {
|
480
|
+
var results = this.searchResults;
|
481
|
+
var visiblePages = [];
|
482
|
+
if (null == results) return false;
|
483
|
+
if (this.constMode2up == this.mode) {
|
484
|
+
visiblePages = [this.twoPage.currentIndexL, this.twoPage.currentIndexR];
|
485
|
+
} else if (this.constMode1up == this.mode) {
|
486
|
+
visiblePages = [this.currentIndex()];
|
487
|
+
} else {
|
488
|
+
return false;
|
489
|
+
}
|
490
|
+
results.matches.some(match => {
|
491
|
+
return match.par[0].boxes.some(box => {
|
492
|
+
var pageIndex = this.book.leafNumToIndex(box.page);
|
493
|
+
if (jQuery.inArray(pageIndex, visiblePages) >= 0) {
|
494
|
+
return true;
|
495
|
+
}
|
496
|
+
});
|
497
|
+
});
|
498
|
+
return false;
|
499
|
+
};
|
@@ -0,0 +1,42 @@
|
|
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
|
+
var preTagRe = escapeRegExp(escapeHTML(preTag));
|
14
|
+
var postTagRe = escapeRegExp(escapeHTML(postTag));
|
15
|
+
// [^] matches any character, including line breaks
|
16
|
+
var regex = new RegExp("".concat(preTagRe, "([^]+?)").concat(postTagRe), 'g');
|
17
|
+
return escapeHTML(match).replace(regex, '<mark>$1</mark>')
|
18
|
+
// Fix trailing hyphens. This over-corrects but is net useful.
|
19
|
+
.replace(/(\b)- /g, '$1');
|
20
|
+
}
|
21
|
+
|
22
|
+
/**
|
23
|
+
* Attach some fields to search inside results
|
24
|
+
* @param {SearchInsideResults} results
|
25
|
+
* @param {(pageNum: LeafNum) => PageNumString} displayPageNumberFn
|
26
|
+
* @param {string} preTag
|
27
|
+
* @param {string} postTag
|
28
|
+
*/
|
29
|
+
export function marshallSearchResults(results, displayPageNumberFn, preTag, postTag) {
|
30
|
+
// Attach matchIndex to a few things to make it easier to identify
|
31
|
+
// an active/selected match
|
32
|
+
for (var [index, match] of results.matches.entries()) {
|
33
|
+
match.matchIndex = index;
|
34
|
+
match.displayPageNumber = displayPageNumberFn(match.par[0].page);
|
35
|
+
match.html = renderMatch(match.text, preTag, postTag);
|
36
|
+
for (var par of match.par) {
|
37
|
+
for (var box of par.boxes) {
|
38
|
+
box.matchIndex = index;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|