Julian's html-search-bar work
This commit is contained in:
parent
e98eba1b11
commit
da57e0f89e
@ -245,7 +245,7 @@ html[dir='rtl'] #sidebarContent {
|
||||
0 1px 1px hsla(0,0%,0%,.1);
|
||||
}
|
||||
|
||||
#toolbarViewer {
|
||||
#toolbarViewer, .findbar {
|
||||
position: relative;
|
||||
height: 32px;
|
||||
background-image: url(images/texture.png),
|
||||
@ -265,6 +265,32 @@ html[dir='rtl'] #sidebarContent {
|
||||
0 1px 0 hsla(0,0%,0%,.15),
|
||||
0 1px 1px hsla(0,0%,0%,.1);
|
||||
}
|
||||
|
||||
.findbar {
|
||||
top: 40px;
|
||||
left: 40px;
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
height: 20px;
|
||||
|
||||
min-width: 16px;
|
||||
padding: 3px 6px 3px 6px;
|
||||
margin: 4px 2px 4px 0;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
color: hsl(0,0%,85%);
|
||||
font-size: 12px;
|
||||
line-height: 14px;
|
||||
text-align: left;
|
||||
-webkit-user-select:none;
|
||||
-moz-user-select:none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.notFound {
|
||||
background-color: rgb(255, 137, 153);
|
||||
}
|
||||
|
||||
html[dir='ltr'] #toolbarViewerLeft {
|
||||
margin-left: -1px;
|
||||
}
|
||||
@ -1069,6 +1095,30 @@ canvas {
|
||||
white-space:pre;
|
||||
}
|
||||
|
||||
.textLayer .highlight {
|
||||
margin: -1px;
|
||||
padding: 1px;
|
||||
|
||||
background-color: rgba(0, 137, 26, 0.2);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.textLayer .highlight.begin {
|
||||
border-radius: 4px 0px 0px 4px;
|
||||
}
|
||||
|
||||
.textLayer .highlight.end {
|
||||
border-radius: 0px 4px 4px 0px;
|
||||
}
|
||||
|
||||
.textLayer .highlight.middle {
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.textLayer .highlight.selected {
|
||||
background-color: rgba(255, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||
so we can override the opaque grey background when the window is inactive;
|
||||
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
||||
|
@ -108,9 +108,20 @@ limitations under the License.
|
||||
</div> <!-- sidebarContainer -->
|
||||
|
||||
<div id="mainContainer">
|
||||
<div class="findbar hidden" id="findbar">
|
||||
<label for="findInput">Find: </label>
|
||||
<input id="findInput" type="search">
|
||||
<button id="findPrevious"><</button>
|
||||
<button id="findNext">></button>
|
||||
<input type="checkbox" id="findHighlightAll">
|
||||
<label for="findHighlightAll">Highlight all</label>
|
||||
<input type="checkbox" id="findMatchCase">
|
||||
<label for="findMatchCase">Match case</label>
|
||||
<span id="findMsgWrap" class="hidden">Reached end of page, continued from top</span>
|
||||
<span id="findMsgNotFound" class="hidden">Phrase not found</span>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<div id="toolbarContainer">
|
||||
|
||||
<div id="toolbarViewer">
|
||||
<div id="toolbarViewerLeft">
|
||||
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="4" data-l10n-id="toggle_slider">
|
||||
|
563
web/viewer.js
563
web/viewer.js
@ -208,6 +208,345 @@ var Settings = (function SettingsClosure() {
|
||||
var cache = new Cache(kCacheSize);
|
||||
var currentPageNumber = 1;
|
||||
|
||||
var PDFFindController = {
|
||||
startedTextExtraction: false,
|
||||
|
||||
// If active, search resulsts will be highlighted.
|
||||
active: false,
|
||||
|
||||
// Stores the text for each page.
|
||||
pageContents: [],
|
||||
|
||||
pageMatches: [],
|
||||
|
||||
selected: {
|
||||
pageIdx: 0,
|
||||
matchIdx: 0
|
||||
},
|
||||
|
||||
dirtyMatch: false,
|
||||
|
||||
findTimeout: null,
|
||||
|
||||
initialize: function() {
|
||||
var events = [
|
||||
'find',
|
||||
'findagain',
|
||||
'findhighlightallchange',
|
||||
'findcasesensitivitychange'
|
||||
];
|
||||
|
||||
this.handelEvent = this.handelEvent.bind(this);
|
||||
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
window.addEventListener(events[i], this.handelEvent);
|
||||
}
|
||||
},
|
||||
|
||||
calcFindMatch: function(pageContent) {
|
||||
// TODO: Handle the other search options here as well.
|
||||
|
||||
var query = this.state.query;
|
||||
var queryLen = query.length;
|
||||
|
||||
if (queryLen === 0)
|
||||
return [];
|
||||
|
||||
var matches = [];
|
||||
|
||||
var matchIdx = -queryLen;
|
||||
while (true) {
|
||||
matchIdx = pageContent.indexOf(query, matchIdx + queryLen);
|
||||
if (matchIdx === -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
matches.push(matchIdx);
|
||||
}
|
||||
return matches;
|
||||
},
|
||||
|
||||
extractText: function() {
|
||||
if (this.startedTextExtraction)
|
||||
return;
|
||||
this.startedTextExtraction = true;
|
||||
var self = this;
|
||||
function extractPageText(pageIndex) {
|
||||
PDFView.pages[pageIndex].getTextContent().then(
|
||||
function textContentResolved(data) {
|
||||
// Bulid the search string.
|
||||
var bidiTexts = data.bidiTexts;
|
||||
var str = '';
|
||||
|
||||
for (var i = 0; i < bidiTexts.length; i++) {
|
||||
str += bidiTexts[i].str;
|
||||
}
|
||||
|
||||
// Store the pageContent as a string.
|
||||
self.pageContents.push(str);
|
||||
// Ensure there is a empty array of matches.
|
||||
self.pageMatches.push([]);
|
||||
|
||||
if ((pageIndex + 1) < PDFView.pages.length)
|
||||
extractPageText(pageIndex + 1);
|
||||
}
|
||||
);
|
||||
}
|
||||
extractPageText(0);
|
||||
},
|
||||
|
||||
handelEvent: function(e) {
|
||||
this.state = e.detail;
|
||||
if (e.detail.findPrevious === undefined) {
|
||||
this.dirtyMatch = true;
|
||||
}
|
||||
|
||||
clearTimeout(this.findTimeout);
|
||||
if (e.type === 'find') {
|
||||
// Only trigger the find action after 250ms of silence.
|
||||
this.findTimeout = setTimeout(this.performFind.bind(this), 250);
|
||||
} else {
|
||||
this.performFind();
|
||||
}
|
||||
},
|
||||
|
||||
updatePage: function(idx) {
|
||||
var page = PDFView.pages[idx];
|
||||
|
||||
if (page.textLayer) {
|
||||
page.textLayer.updateMatches();
|
||||
} else if (this.selected.pageIdx === idx) {
|
||||
// If the page is selected, scroll the page into view, which triggers
|
||||
// rendering the page, which adds the textLayer. Once the textLayer is
|
||||
// build, it will scroll onto the selected match.
|
||||
page.scrollIntoView();
|
||||
}
|
||||
},
|
||||
|
||||
performFind: function() {
|
||||
// Recalculate all the matches.
|
||||
// TODO: Make one match show up as the current match
|
||||
|
||||
var pages = PDFView.pages;
|
||||
var pageContents = this.pageContents;
|
||||
var pageMatches = this.pageMatches;
|
||||
|
||||
this.active = true;
|
||||
|
||||
if (this.dirtyMatch) {
|
||||
// Need to recalculate the matches.
|
||||
this.dirtyMatch = false;
|
||||
|
||||
this.selected = {
|
||||
pageIdx: -1,
|
||||
matchIdx: -1
|
||||
};
|
||||
|
||||
// TODO: Make this way more lasily (aka. efficient) - e.g. calculate only
|
||||
// the matches for the current visible pages.
|
||||
var firstMatch = true;
|
||||
for (var i = 0; i < pageContents.length; i++) {
|
||||
var matches = pageMatches[i] = this.calcFindMatch(pageContents[i]);
|
||||
if (firstMatch && matches.length !== 0) {
|
||||
firstMatch = false;
|
||||
this.selected = {
|
||||
pageIdx: i,
|
||||
matchIdx: 0
|
||||
};
|
||||
}
|
||||
this.updatePage(i, true);
|
||||
}
|
||||
} else {
|
||||
// If there is NO selection, then there is no match at all -> no sense to
|
||||
// handel previous/next action.
|
||||
if (this.selected.pageIdx === -1)
|
||||
return;
|
||||
|
||||
// Handle findAgain case.
|
||||
var previous = this.state.findPrevious;
|
||||
var sPageIdx = this.selected.pageIdx;
|
||||
var sMatchIdx = this.selected.matchIdx;
|
||||
|
||||
if (previous) {
|
||||
// Select previous match.
|
||||
|
||||
if (sMatchIdx !== 0) {
|
||||
this.selected.matchIdx -= 1;
|
||||
} else {
|
||||
var len = pageMatches.length;
|
||||
for (var i = sPageIdx - 1; i != sPageIdx; i--) {
|
||||
if (i < 0)
|
||||
i += len;
|
||||
|
||||
if (pageMatches[i].length !== 0) {
|
||||
this.selected = {
|
||||
pageIdx: i,
|
||||
matchIdx: pageMatches[i].length - 1
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If pageIdx stayed the same, select last match on the page.
|
||||
if (this.selected.pageIdx === sPageIdx) {
|
||||
this.selected.matchIdx = pageMatches[sPageIdx].length - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Select next match.
|
||||
|
||||
if (pageMatches[sPageIdx].length !== sMatchIdx + 1) {
|
||||
this.selected.matchIdx += 1;
|
||||
} else {
|
||||
var len = pageMatches.length;
|
||||
for (var i = sPageIdx + 1; i < len + sPageIdx; i++) {
|
||||
if (pageMatches[i % len].length !== 0) {
|
||||
this.selected = {
|
||||
pageIdx: i % len,
|
||||
matchIdx: 0
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If pageIdx stayed the same, select last match on the page.
|
||||
if (this.selected.pageIdx === sPageIdx) {
|
||||
this.selected.matchIdx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.updatePage(sPageIdx, sPageIdx === this.selected.pageIdx);
|
||||
if (sPageIdx !== this.selected.pageIdx) {
|
||||
this.updatePage(this.selected.pageIdx, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var PDFFindBar = {
|
||||
// TODO: Enable the FindBar *AFTER* the pagesPromise in the load function
|
||||
// got resolved
|
||||
|
||||
opened: false,
|
||||
|
||||
FIND_FOUND: 0, // Successful find
|
||||
FIND_NOTFOUND: 1, // Unsuccessful find
|
||||
FIND_WRAPPED: 2, // Successful find, but wrapped around
|
||||
|
||||
initialize: function() {
|
||||
this.bar = document.getElementById('findbar');
|
||||
this.toggleButton = document.getElementById('viewSearch');
|
||||
this.findField = document.getElementById('findInput');
|
||||
this.highlightAll = document.getElementById('findHighlightAll');
|
||||
this.caseSensitive = document.getElementById('findMatchCase');
|
||||
this.findMsgWrap = document.getElementById('findMsgWrap');
|
||||
this.findMsgNotFound = document.getElementById('findMsgNotFound');
|
||||
|
||||
var self = this;
|
||||
this.toggleButton.addEventListener('click',
|
||||
function() {
|
||||
self.toggle();
|
||||
});
|
||||
|
||||
this.findField.addEventListener('input', function() {
|
||||
self.dispatchEvent('');
|
||||
});
|
||||
|
||||
// TODO: Add keybindings like enter, shift-enter, CMD-G etc. to go to prev/
|
||||
// next match when the findField is selected.
|
||||
|
||||
document.getElementById('findPrevious').addEventListener('click',
|
||||
function() {
|
||||
self.dispatchEvent('again', true);
|
||||
});
|
||||
|
||||
document.getElementById('findNext').addEventListener('click',
|
||||
function() {
|
||||
self.dispatchEvent('again', false);
|
||||
});
|
||||
|
||||
this.highlightAll.addEventListener('click',
|
||||
function() {
|
||||
self.dispatchEvent('highlightallchange');
|
||||
});
|
||||
|
||||
this.caseSensitive.addEventListener('click',
|
||||
function() {
|
||||
self.dispatchEvent('casesensitivitychange');
|
||||
});
|
||||
},
|
||||
|
||||
dispatchEvent: function(aType, aFindPrevious) {
|
||||
var event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('find' + aType, true, true, {
|
||||
query: this.findField.value,
|
||||
caseSensitive: this.caseSensitive.checked,
|
||||
highlightAll: this.highlightAll.checked,
|
||||
findPrevious: aFindPrevious
|
||||
});
|
||||
return window.dispatchEvent(event);
|
||||
},
|
||||
|
||||
updateUIState: function(aState) {
|
||||
var notFound = false;
|
||||
var wrapped = false;
|
||||
|
||||
switch (aState) {
|
||||
case this.FIND_FOUND:
|
||||
break;
|
||||
|
||||
case this.FIND_NOTFOUND:
|
||||
notFound = true;
|
||||
break;
|
||||
|
||||
case this.FIND_WRAPPED:
|
||||
wrapped = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (notFound) {
|
||||
this.findField.classList.add('notFound');
|
||||
this.findMsgNotFound.classList.remove('hidden');
|
||||
} else {
|
||||
this.findField.classList.remove('notFound');
|
||||
this.findMsgNotFound.classList.add('hidden');
|
||||
}
|
||||
|
||||
if (wrapped) {
|
||||
this.findMsgWrap.classList.remove('hidden');
|
||||
} else {
|
||||
this.findMsgWrap.classList.add('hidden');
|
||||
}
|
||||
},
|
||||
|
||||
open: function() {
|
||||
if (this.opened) return;
|
||||
|
||||
this.opened = true;
|
||||
this.toggleButton.classList.add('toggled');
|
||||
this.bar.classList.remove('hidden');
|
||||
this.findField.select();
|
||||
this.findField.focus();
|
||||
},
|
||||
|
||||
close: function() {
|
||||
if (!this.opened) return;
|
||||
|
||||
this.opened = false;
|
||||
this.toggleButton.classList.remove('toggled');
|
||||
this.bar.classList.add('hidden');
|
||||
|
||||
PDFFindController.active = false;
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this.opened) {
|
||||
this.close();
|
||||
} else {
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var PDFView = {
|
||||
pages: [],
|
||||
thumbnails: [],
|
||||
@ -242,6 +581,9 @@ var PDFView = {
|
||||
this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
|
||||
this.renderHighestPriority.bind(this));
|
||||
|
||||
PDFFindBar.initialize();
|
||||
PDFFindController.initialize();
|
||||
|
||||
this.initialized = true;
|
||||
container.addEventListener('scroll', function() {
|
||||
self.lastScroll = Date.now();
|
||||
@ -736,6 +1078,9 @@ var PDFView = {
|
||||
thumbnails.push(thumbnailView);
|
||||
var pageRef = page.ref;
|
||||
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
||||
|
||||
// Trigger text extraction. TODO: Make this happen lasyliy if needed.
|
||||
PDFFindController.extractText();
|
||||
}
|
||||
|
||||
self.pagesRefMap = pagesRefMap;
|
||||
@ -1229,6 +1574,7 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
this.resume = null;
|
||||
|
||||
this.textContent = null;
|
||||
this.textLayer = null;
|
||||
|
||||
var anchor = document.createElement('a');
|
||||
anchor.name = '' + this.id;
|
||||
@ -1475,7 +1821,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
||||
textLayerDiv.className = 'textLayer';
|
||||
div.appendChild(textLayerDiv);
|
||||
}
|
||||
var textLayer = textLayerDiv ? new TextLayerBuilder(textLayerDiv) : null;
|
||||
var textLayer = this.textLayer =
|
||||
textLayerDiv ? new TextLayerBuilder(textLayerDiv, this.id - 1) : null;
|
||||
|
||||
var scale = this.scale, viewport = this.viewport;
|
||||
canvas.width = viewport.width;
|
||||
@ -1834,21 +2181,25 @@ var CustomStyle = (function CustomStyleClosure() {
|
||||
return CustomStyle;
|
||||
})();
|
||||
|
||||
var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||
var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) {
|
||||
var textLayerFrag = document.createDocumentFragment();
|
||||
|
||||
this.textLayerDiv = textLayerDiv;
|
||||
this.layoutDone = false;
|
||||
this.divContentDone = false;
|
||||
this.pageIdx = pageIdx;
|
||||
this.matches = [];
|
||||
|
||||
this.beginLayout = function textLayerBuilderBeginLayout() {
|
||||
this.textDivs = [];
|
||||
this.textLayerQueue = [];
|
||||
this.renderingDone = false;
|
||||
};
|
||||
|
||||
this.endLayout = function textLayerBuilderEndLayout() {
|
||||
this.layoutDone = true;
|
||||
this.insertDivContent();
|
||||
},
|
||||
};
|
||||
|
||||
this.renderLayer = function textLayerBuilderRenderLayer() {
|
||||
var self = this;
|
||||
@ -1862,8 +2213,11 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||
if (textDivs.length > 100000)
|
||||
return;
|
||||
|
||||
while (textDivs.length > 0) {
|
||||
var textDiv = textDivs.shift();
|
||||
var i = textDivs.length;
|
||||
|
||||
while (i !== 0) {
|
||||
i--;
|
||||
var textDiv = textDivs[i];
|
||||
textLayerFrag.appendChild(textDiv);
|
||||
|
||||
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
||||
@ -1875,9 +2229,14 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||
CustomStyle.setProp('transform' , textDiv,
|
||||
'scale(' + textScale + ', 1)');
|
||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||
|
||||
textLayerDiv.appendChild(textDiv);
|
||||
}
|
||||
}
|
||||
|
||||
this.renderingDone = true;
|
||||
this.updateMatches();
|
||||
|
||||
textLayerDiv.appendChild(textLayerFrag);
|
||||
};
|
||||
|
||||
@ -1944,6 +2303,184 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
||||
this.textContent = textContent;
|
||||
this.insertDivContent();
|
||||
};
|
||||
|
||||
this.convertMatches = function textLayerBuilderConvertMatches(matches) {
|
||||
var i = 0;
|
||||
var iIndex = 0;
|
||||
var bidiTexts = this.textContent.bidiTexts;
|
||||
var end = bidiTexts.length - 1;
|
||||
var queryLen = PDFFindController.state.query.length;
|
||||
|
||||
var lastDivIdx = -1;
|
||||
var pos;
|
||||
|
||||
var ret = [];
|
||||
|
||||
// Loop over all the matches.
|
||||
for (var m = 0; m < matches.length; m++) {
|
||||
var matchIdx = matches[m];
|
||||
// # Calculate the begin position.
|
||||
|
||||
// Loop over the divIdxs.
|
||||
while (i !== end && matchIdx >= (iIndex + bidiTexts[i].str.length)) {
|
||||
iIndex += bidiTexts[i].str.length;
|
||||
i++;
|
||||
}
|
||||
|
||||
// TODO: Do proper handling here if something goes wrong.
|
||||
if (i == bidiTexts.length) {
|
||||
console.error('Could not find matching mapping');
|
||||
}
|
||||
|
||||
var match = {
|
||||
begin: {
|
||||
divIdx: i,
|
||||
offset: matchIdx - iIndex
|
||||
}
|
||||
};
|
||||
|
||||
// # Calculate the end position.
|
||||
matchIdx += queryLen;
|
||||
|
||||
// Somewhat same array as above, but use a > instead of >= to get the end
|
||||
// position right.
|
||||
while (i !== end && matchIdx > (iIndex + bidiTexts[i].str.length)) {
|
||||
iIndex += bidiTexts[i].str.length;
|
||||
i++;
|
||||
}
|
||||
|
||||
match.end = {
|
||||
divIdx: i,
|
||||
offset: matchIdx - iIndex
|
||||
};
|
||||
ret.push(match);
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
this.renderMatches = function textLayerBuilder_renderMatches(matches) {
|
||||
var bidiTexts = this.textContent.bidiTexts;
|
||||
var textDivs = this.textDivs;
|
||||
var prevEnd = null;
|
||||
var isSelectedPage = this.pageIdx === PDFFindController.selected.pageIdx;
|
||||
var selectedMatchIdx = PDFFindController.selected.matchIdx;
|
||||
|
||||
var infty = {
|
||||
divIdx: -1,
|
||||
offset: undefined
|
||||
};
|
||||
|
||||
function beginText(begin, className) {
|
||||
var divIdx = begin.divIdx;
|
||||
var div = textDivs[divIdx];
|
||||
div.innerHTML = '';
|
||||
|
||||
var content = bidiTexts[divIdx].str.substring(0, begin.offset);
|
||||
var node = document.createTextNode(content);
|
||||
if (className) {
|
||||
var isSelected = isSelectedPage &&
|
||||
divIdx === selectedMatchIdx;
|
||||
var span = document.createElement('span');
|
||||
span.className = className + (isSelected ? ' selected' : '');
|
||||
span.appendChild(node);
|
||||
div.appendChild(span);
|
||||
return;
|
||||
}
|
||||
div.appendChild(node);
|
||||
}
|
||||
|
||||
function appendText(from, to, className) {
|
||||
var divIdx = from.divIdx;
|
||||
var div = textDivs[divIdx];
|
||||
|
||||
var content = bidiTexts[divIdx].str.substring(from.offset, to.offset);
|
||||
var node = document.createTextNode(content);
|
||||
if (className) {
|
||||
var span = document.createElement('span');
|
||||
span.className = className;
|
||||
span.appendChild(node);
|
||||
div.appendChild(span);
|
||||
return;
|
||||
}
|
||||
div.appendChild(node);
|
||||
}
|
||||
|
||||
function highlightDiv(divIdx, className) {
|
||||
textDivs[divIdx].className = className;
|
||||
}
|
||||
|
||||
for (var i = 0; i < matches.length; i++) {
|
||||
var match = matches[i];
|
||||
var begin = match.begin;
|
||||
var end = match.end;
|
||||
|
||||
var isSelected = isSelectedPage && i === selectedMatchIdx;
|
||||
var highlightSuffix = (isSelected ? ' selected' : '');
|
||||
if (isSelected)
|
||||
scrollIntoView(textDivs[begin.divIdx], {top: -50});
|
||||
|
||||
// Match inside new div.
|
||||
if (!prevEnd || begin.divIdx !== prevEnd.divIdx) {
|
||||
// If there was a previous div, then add the text at the end
|
||||
if (prevEnd !== null) {
|
||||
appendText(prevEnd, infty);
|
||||
}
|
||||
// clears the divs and set the content until the begin point.
|
||||
beginText(begin);
|
||||
} else {
|
||||
appendText(prevEnd, begin);
|
||||
}
|
||||
|
||||
if (begin.divIdx === end.divIdx) {
|
||||
appendText(begin, end, 'highlight' + highlightSuffix);
|
||||
} else {
|
||||
appendText(begin, infty, 'highlight begin' + highlightSuffix);
|
||||
for (var n = begin.divIdx + 1; n < end.divIdx; n++) {
|
||||
highlightDiv(n, 'highlight middle' + highlightSuffix);
|
||||
}
|
||||
beginText(end, 'highlight end' + highlightSuffix);
|
||||
}
|
||||
prevEnd = end;
|
||||
}
|
||||
|
||||
if (prevEnd) {
|
||||
appendText(prevEnd, infty);
|
||||
}
|
||||
};
|
||||
|
||||
this.updateMatches = function textLayerUpdateMatches() {
|
||||
// Only show matches, once all rendering is done.
|
||||
if (!this.renderingDone)
|
||||
return;
|
||||
|
||||
// Clear out all matches.
|
||||
var matches = this.matches;
|
||||
var textDivs = this.textDivs;
|
||||
var bidiTexts = this.textContent.bidiTexts;
|
||||
var clearedUntilDivIdx = -1;
|
||||
|
||||
for (var i = 0; i < matches.length; i++) {
|
||||
var match = matches[i];
|
||||
var begin = Math.max(clearedUntilDivIdx, match.begin.divIdx);
|
||||
for (var n = begin; n <= match.end.divIdx; n++) {
|
||||
var div = bidiTexts[n].str;
|
||||
div.textContent = div.textContent;
|
||||
div.className = '';
|
||||
}
|
||||
clearedUntilDivIdx = match.end.divIdx + 1;
|
||||
}
|
||||
|
||||
if (!PDFFindController.active)
|
||||
return;
|
||||
|
||||
// Convert the matches on the page controller into the match format used
|
||||
// for the textLayer.
|
||||
this.matches = matches =
|
||||
this.convertMatches(PDFFindController.pageMatches[this.pageIdx] || []);
|
||||
|
||||
this.renderMatches(this.matches);
|
||||
};
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
||||
@ -2059,16 +2596,6 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
||||
PDFView.switchSidebarView('outline');
|
||||
});
|
||||
|
||||
document.getElementById('viewSearch').addEventListener('click',
|
||||
function() {
|
||||
PDFView.switchSidebarView('search');
|
||||
});
|
||||
|
||||
document.getElementById('searchButton').addEventListener('click',
|
||||
function() {
|
||||
PDFView.search();
|
||||
});
|
||||
|
||||
document.getElementById('previous').addEventListener('click',
|
||||
function() {
|
||||
PDFView.page--;
|
||||
@ -2331,6 +2858,12 @@ window.addEventListener('keydown', function keydown(evt) {
|
||||
// control is selected or not.
|
||||
if (cmd == 1 || cmd == 8) { // either CTRL or META key.
|
||||
switch (evt.keyCode) {
|
||||
//#if !(FIREFOX || MOZCENTRAL)
|
||||
case 70:
|
||||
PDFFindBar.toggle();
|
||||
handled = true;
|
||||
break;
|
||||
//#endif
|
||||
case 61: // FF/Mac '='
|
||||
case 107: // FF '+' and '='
|
||||
case 187: // Chrome '+'
|
||||
|
Loading…
Reference in New Issue
Block a user