commit
4e0c792f12
@ -315,8 +315,8 @@ ChromeActions.prototype = {
|
|||||||
pdfBugEnabled: function() {
|
pdfBugEnabled: function() {
|
||||||
return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
|
return getBoolPref(PREF_PREFIX + '.pdfBugEnabled', false);
|
||||||
},
|
},
|
||||||
searchEnabled: function() {
|
findEnabled: function() {
|
||||||
return getBoolPref(PREF_PREFIX + '.searchEnabled', false);
|
return getBoolPref(PREF_PREFIX + '.findEnabled', false);
|
||||||
},
|
},
|
||||||
fallback: function(url, sendResponse) {
|
fallback: function(url, sendResponse) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
@ -36,8 +36,8 @@ outline.title=إظهار ملخص المستند
|
|||||||
outline_label=ملخص المستند
|
outline_label=ملخص المستند
|
||||||
thumbs.title=إظهار الصور المصغرة
|
thumbs.title=إظهار الصور المصغرة
|
||||||
thumbs_label=الصور المصغرة
|
thumbs_label=الصور المصغرة
|
||||||
search_panel.title=البحث في المستند
|
find_panel.title=البحث في المستند
|
||||||
search_panel_label=بحث
|
find_panel_label=بحث
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=لا يوجد ملخص
|
no_outline=لا يوجد ملخص
|
||||||
@ -54,9 +54,9 @@ thumb_page_canvas=صورة مصغرة من الصفحة {{page}}
|
|||||||
page_rotate_cw.label=تدوير مع عقارب الساعة
|
page_rotate_cw.label=تدوير مع عقارب الساعة
|
||||||
page_rotate_ccw.label=تدوير عكس عقارب الساعة
|
page_rotate_ccw.label=تدوير عكس عقارب الساعة
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=بحث
|
find=بحث
|
||||||
search_terms_not_found=(لا يوجد)
|
find_terms_not_found=(لا يوجد)
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=مزيد من المعلومات
|
error_more_info=مزيد من المعلومات
|
||||||
|
@ -36,8 +36,8 @@ outline.title=Vis dokumentoversigt
|
|||||||
outline_label=Dokumentoversigt
|
outline_label=Dokumentoversigt
|
||||||
thumbs.title=Vis thumbnails
|
thumbs.title=Vis thumbnails
|
||||||
thumbs_label=Thumbnails
|
thumbs_label=Thumbnails
|
||||||
search_panel.title=Søg i dokumentet
|
find_panel.title=Søg i dokumentet
|
||||||
search_panel_label=Søg
|
find_panel_label=Søg
|
||||||
|
|
||||||
# Dokumentoversigtsbeskeder
|
# Dokumentoversigtsbeskeder
|
||||||
no_outline=Ingen dokumentoversigt tilgængelig
|
no_outline=Ingen dokumentoversigt tilgængelig
|
||||||
@ -51,8 +51,8 @@ thumb_page_title=Side {{page}}
|
|||||||
thumb_page_canvas=Thumbnail af side {{page}}
|
thumb_page_canvas=Thumbnail af side {{page}}
|
||||||
|
|
||||||
# Søgepanelet
|
# Søgepanelet
|
||||||
search=Søg
|
find=Søg
|
||||||
search_terms_not_found=(Ikke fundet)
|
find_terms_not_found=(Ikke fundet)
|
||||||
|
|
||||||
# Fejlpanel
|
# Fejlpanel
|
||||||
error_more_info=Mere information
|
error_more_info=Mere information
|
||||||
|
@ -36,8 +36,6 @@ outline.title=Show Document Outline
|
|||||||
outline_label=Document Outline
|
outline_label=Document Outline
|
||||||
thumbs.title=Show Thumbnails
|
thumbs.title=Show Thumbnails
|
||||||
thumbs_label=Thumbnails
|
thumbs_label=Thumbnails
|
||||||
search_panel.title=Search Document
|
|
||||||
search_panel_label=Search
|
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=No Outline Available
|
no_outline=No Outline Available
|
||||||
@ -54,9 +52,15 @@ thumb_page_canvas=Thumbnail of Page {{page}}
|
|||||||
page_rotate_cw.label=Rotate Clockwise
|
page_rotate_cw.label=Rotate Clockwise
|
||||||
page_rotate_ccw.label=Rotate Counter-Clockwise
|
page_rotate_ccw.label=Rotate Counter-Clockwise
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=Find
|
find.title=Find in Document
|
||||||
search_terms_not_found=(Not found)
|
find_label=Find
|
||||||
|
find_previous.title=Find the previous occurrence of the phrase
|
||||||
|
find_next.title=Find the next occurrence of the phrase
|
||||||
|
find_highlight=Highlight all
|
||||||
|
find_match_case_label=Match case
|
||||||
|
find_wrapped_to_bottom=Reached end of page, continued from bottom
|
||||||
|
find_wrapped_to_top=Reached end of page, continued from top
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=More Information
|
error_more_info=More Information
|
||||||
|
@ -36,8 +36,8 @@ outline.title=Mostrar esquema del documento
|
|||||||
outline_label=Esquema del documento
|
outline_label=Esquema del documento
|
||||||
thumbs.title=Mostrar miniaturas
|
thumbs.title=Mostrar miniaturas
|
||||||
thumbs_label=Miniaturas
|
thumbs_label=Miniaturas
|
||||||
search_panel.title=Buscar en el documento
|
find_panel.title=Buscar en el documento
|
||||||
search_panel_label=Buscar
|
find_panel_label=Buscar
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=No hay un esquema disponible
|
no_outline=No hay un esquema disponible
|
||||||
@ -50,9 +50,9 @@ thumb_page_title=Página {{page}}
|
|||||||
# number.
|
# number.
|
||||||
thumb_page_canvas=Miniatura de la página {{page}}
|
thumb_page_canvas=Miniatura de la página {{page}}
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=Buscar
|
find=Buscar
|
||||||
search_terms_not_found=(No encontrado)
|
find_terms_not_found=(No encontrado)
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=Más información
|
error_more_info=Más información
|
||||||
|
@ -36,8 +36,8 @@ outline.title=Näytä asiakirjan jäsennys
|
|||||||
outline_label=Asiakirjan jäsennys
|
outline_label=Asiakirjan jäsennys
|
||||||
thumbs.title=Näytä esikatselukuvat
|
thumbs.title=Näytä esikatselukuvat
|
||||||
thumbs_label=Esikatselukuvat
|
thumbs_label=Esikatselukuvat
|
||||||
search_panel.title=Etsi asiakirjasta
|
find_panel.title=Etsi asiakirjasta
|
||||||
search_panel_label=Etsi
|
find_panel_label=Etsi
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=Jäsennystä ei ole tarjolla
|
no_outline=Jäsennystä ei ole tarjolla
|
||||||
@ -50,9 +50,9 @@ thumb_page_title=Sivu {{page}}
|
|||||||
# number.
|
# number.
|
||||||
thumb_page_canvas=Sivun {{page}} esikatselukuva
|
thumb_page_canvas=Sivun {{page}} esikatselukuva
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=Etsi
|
find=Etsi
|
||||||
search_terms_not_found=(Ei löytynyt)
|
find_terms_not_found=(Ei löytynyt)
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=Enemmän tietoa
|
error_more_info=Enemmän tietoa
|
||||||
|
@ -36,8 +36,8 @@ outline.title=文書の目次
|
|||||||
outline_label=文書の目次
|
outline_label=文書の目次
|
||||||
thumbs.title=縮小版
|
thumbs.title=縮小版
|
||||||
thumbs_label=縮小版
|
thumbs_label=縮小版
|
||||||
search_panel.title=検索
|
find_panel.title=検索
|
||||||
search_panel_label=検索
|
find_panel_label=検索
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=利用可能な目次はありません
|
no_outline=利用可能な目次はありません
|
||||||
@ -54,9 +54,9 @@ thumb_page_canvas=ページの縮小版 {{page}}
|
|||||||
page_rotate_cw.label=右回転
|
page_rotate_cw.label=右回転
|
||||||
page_rotate_ccw.label=左回転
|
page_rotate_ccw.label=左回転
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=検索
|
find=検索
|
||||||
search_terms_not_found=(見つかりませんでした)
|
find_terms_not_found=(見つかりませんでした)
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=詳細情報
|
error_more_info=詳細情報
|
||||||
|
@ -34,8 +34,8 @@ outline.title=Toon document structuur
|
|||||||
outline_label=Document structuur
|
outline_label=Document structuur
|
||||||
thumbs.title=Toon miniaturen
|
thumbs.title=Toon miniaturen
|
||||||
thumbs_label=Miniaturen
|
thumbs_label=Miniaturen
|
||||||
search_panel.title=Doorzoek document
|
find_panel.title=Doorzoek document
|
||||||
search_panel_label=Zoek
|
find_panel_label=Zoek
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=Geen structuur beschikbaar
|
no_outline=Geen structuur beschikbaar
|
||||||
@ -48,9 +48,9 @@ thumb_page_title=Pagina {{page}}
|
|||||||
# number.
|
# number.
|
||||||
thumb_page_canvas=Miniatuur van pagina {{page}}
|
thumb_page_canvas=Miniatuur van pagina {{page}}
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=Zoek
|
find=Zoek
|
||||||
search_terms_not_found=(Niet gevonden)
|
find_terms_not_found=(Niet gevonden)
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=Meer informatie
|
error_more_info=Meer informatie
|
||||||
|
@ -34,8 +34,8 @@ outline.title=Visa dokumentdisposition
|
|||||||
outline_label=Dokumentdisposition
|
outline_label=Dokumentdisposition
|
||||||
thumbs.title=Visa miniatyrer
|
thumbs.title=Visa miniatyrer
|
||||||
thumbs_label=Miniatyrer
|
thumbs_label=Miniatyrer
|
||||||
search_panel.title=Sök i dokumentet
|
find_panel.title=Sök i dokumentet
|
||||||
search_panel_label=Sök
|
find_panel_label=Sök
|
||||||
|
|
||||||
# Document outline messages
|
# Document outline messages
|
||||||
no_outline=Ingen dokumentdisposition tillgänglig
|
no_outline=Ingen dokumentdisposition tillgänglig
|
||||||
@ -48,9 +48,9 @@ thumb_page_title=Sida {{page}}
|
|||||||
# number.
|
# number.
|
||||||
thumb_page_canvas=Miniatyr av sida {{page}}
|
thumb_page_canvas=Miniatyr av sida {{page}}
|
||||||
|
|
||||||
# Search panel button title and messages
|
# Find panel button title and messages
|
||||||
search=Hitta
|
find=Hitta
|
||||||
search_terms_not_found=(hittades inte)
|
find_terms_not_found=(hittades inte)
|
||||||
|
|
||||||
# Error panel labels
|
# Error panel labels
|
||||||
error_more_info=Mer information
|
error_more_info=Mer information
|
||||||
|
@ -34,8 +34,8 @@ outline.title=顯示文件綱要
|
|||||||
outline_label=文件綱要
|
outline_label=文件綱要
|
||||||
thumbs.title=顯示縮圖
|
thumbs.title=顯示縮圖
|
||||||
thumbs_label=縮圖
|
thumbs_label=縮圖
|
||||||
search_panel.title=搜索文件
|
find_panel.title=搜索文件
|
||||||
search_panel_label=搜索
|
find_panel_label=搜索
|
||||||
|
|
||||||
# 文件綱要相關訊息
|
# 文件綱要相關訊息
|
||||||
no_outline=無可用的綱要
|
no_outline=無可用的綱要
|
||||||
@ -51,8 +51,8 @@ page_rotate_cw.label=順時針旋轉
|
|||||||
page_rotate_ccw.label=逆時針旋轉
|
page_rotate_ccw.label=逆時針旋轉
|
||||||
|
|
||||||
# 搜尋面板按鍵文字及訊息
|
# 搜尋面板按鍵文字及訊息
|
||||||
search=搜索
|
find=搜索
|
||||||
search_terms_not_found=(沒有找到)
|
find_terms_not_found=(沒有找到)
|
||||||
|
|
||||||
# 錯誤面板標籤
|
# 錯誤面板標籤
|
||||||
error_more_info=更多資訊
|
error_more_info=更多資訊
|
||||||
|
127
web/viewer.css
127
web/viewer.css
@ -245,7 +245,7 @@ html[dir='rtl'] #sidebarContent {
|
|||||||
0 1px 1px hsla(0,0%,0%,.1);
|
0 1px 1px hsla(0,0%,0%,.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbarViewer {
|
#toolbarViewer, .findbar {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
background-image: url(images/texture.png),
|
background-image: url(images/texture.png),
|
||||||
@ -265,6 +265,65 @@ html[dir='rtl'] #sidebarContent {
|
|||||||
0 1px 0 hsla(0,0%,0%,.15),
|
0 1px 0 hsla(0,0%,0%,.15),
|
||||||
0 1px 1px hsla(0,0%,0%,.1);
|
0 1px 1px hsla(0,0%,0%,.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.findbar {
|
||||||
|
top: 32px;
|
||||||
|
left: 68px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
min-width: 16px;
|
||||||
|
padding: 3px 6px 3px 6px;
|
||||||
|
margin: 4px 2px 4px 0;
|
||||||
|
color: hsl(0,0%,85%);
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 14px;
|
||||||
|
text-align: left;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.findbar label {
|
||||||
|
-webkit-user-select:none;
|
||||||
|
-moz-user-select:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doorHanger {
|
||||||
|
border: 1px solid hsla(0,0%,0%,.5);
|
||||||
|
border-radius: 2px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
.doorHanger:after, .doorHanger:before {
|
||||||
|
bottom: 100%;
|
||||||
|
border: solid transparent;
|
||||||
|
content: " ";
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.doorHanger:after {
|
||||||
|
border-bottom-color: hsla(0,0%,32%,.99);
|
||||||
|
border-width: 8px;
|
||||||
|
left: 16px;
|
||||||
|
margin-left: -8px;
|
||||||
|
}
|
||||||
|
.doorHanger:before {
|
||||||
|
border-bottom-color: hsla(0,0%,0%,.5);
|
||||||
|
border-width: 9px;
|
||||||
|
left: 16px;
|
||||||
|
margin-left: -9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#findMsg {
|
||||||
|
font-style: italic;
|
||||||
|
color: #A6B7D0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notFound {
|
||||||
|
background-color: rgb(255, 137, 153);
|
||||||
|
}
|
||||||
|
|
||||||
html[dir='ltr'] #toolbarViewerLeft {
|
html[dir='ltr'] #toolbarViewerLeft {
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
}
|
}
|
||||||
@ -702,7 +761,7 @@ html[dir='rtl'] .toolbarButton.pageDown::before {
|
|||||||
content: url(images/toolbarButton-viewOutline.png);
|
content: url(images/toolbarButton-viewOutline.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
#viewSearch.toolbarButton::before {
|
#viewFind.toolbarButton::before {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
content: url(images/toolbarButton-search.png);
|
content: url(images/toolbarButton-search.png);
|
||||||
}
|
}
|
||||||
@ -844,8 +903,7 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
|||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.outlineItem > a,
|
.outlineItem > a {
|
||||||
#searchResults > a {
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 95%;
|
min-width: 95%;
|
||||||
@ -861,8 +919,7 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.outlineItem > a:hover,
|
.outlineItem > a:hover {
|
||||||
#searchResults > a:hover {
|
|
||||||
background-color: hsla(0,0%,100%,.02);
|
background-color: hsla(0,0%,100%,.02);
|
||||||
background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
|
background-image: -moz-linear-gradient(hsla(0,0%,100%,.05), hsla(0,0%,100%,0));
|
||||||
background-clip: padding-box;
|
background-clip: padding-box;
|
||||||
@ -889,7 +946,7 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
|||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchScrollView {
|
#findScrollView {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
@ -897,36 +954,6 @@ a:focus > .thumbnail > .thumbnailSelectionRing,
|
|||||||
width: 280px;
|
width: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchToolbar {
|
|
||||||
padding-left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
padding-top: 0px;
|
|
||||||
padding-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchToolbar > input {
|
|
||||||
margin-left: 4px;
|
|
||||||
width: 124px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchToolbar button {
|
|
||||||
width: auto;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 6px;
|
|
||||||
height: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchResults {
|
|
||||||
overflow: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 30px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
right: 0;
|
|
||||||
padding: 4px 4px 0;
|
|
||||||
font-size: smaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
#sidebarControls {
|
#sidebarControls {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
@ -1069,6 +1096,30 @@ canvas {
|
|||||||
white-space:pre;
|
white-space:pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.textLayer .highlight {
|
||||||
|
margin: -1px;
|
||||||
|
padding: 1px;
|
||||||
|
|
||||||
|
background-color: rgba(180, 0, 170, 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(0, 100, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
/* TODO: file FF bug to support ::-moz-selection:window-inactive
|
||||||
so we can override the opaque grey background when the window is inactive;
|
so we can override the opaque grey background when the window is inactive;
|
||||||
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
see https://bugzilla.mozilla.org/show_bug.cgi?id=706209 */
|
||||||
@ -1291,7 +1342,7 @@ canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media all and (max-width: 600px) {
|
@media all and (max-width: 600px) {
|
||||||
#toolbarViewerRight {
|
#toolbarViewerRight, #findbar, #viewFind {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,35 +88,40 @@ limitations under the License.
|
|||||||
<button id="viewOutline" class="toolbarButton group" title="Show Document Outline" tabindex="2" data-l10n-id="outline">
|
<button id="viewOutline" class="toolbarButton group" title="Show Document Outline" tabindex="2" data-l10n-id="outline">
|
||||||
<span data-l10n-id="outline_label">Document Outline</span>
|
<span data-l10n-id="outline_label">Document Outline</span>
|
||||||
</button>
|
</button>
|
||||||
<button id="viewSearch" class="toolbarButton group hidden" title="Search Document" tabindex="3" data-l10n-id="search_panel">
|
|
||||||
<span data-l10n-id="search_panel_label">Search Document</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="sidebarContent">
|
<div id="sidebarContent">
|
||||||
<div id="thumbnailView">
|
<div id="thumbnailView">
|
||||||
</div>
|
</div>
|
||||||
<div id="outlineView" class="hidden">
|
<div id="outlineView" class="hidden">
|
||||||
</div>
|
</div>
|
||||||
<div id="searchView" class="hidden">
|
|
||||||
<div id="searchToolbar">
|
|
||||||
<input id="searchTermsInput" class="toolbarField">
|
|
||||||
<button id="searchButton" class="textButton toolbarButton" data-l10n-id="search">Find</button>
|
|
||||||
</div>
|
|
||||||
<div id="searchResults"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- sidebarContainer -->
|
</div> <!-- sidebarContainer -->
|
||||||
|
|
||||||
<div id="mainContainer">
|
<div id="mainContainer">
|
||||||
|
<div class="findbar hidden doorHanger" id="findbar">
|
||||||
|
<label for="findInput" data-l10n-id="find_label">Find</label>:
|
||||||
|
<input id="findInput" type="search">
|
||||||
|
<button id="findPrevious" data-l10n-id="find_previous" title=""><</button>
|
||||||
|
<button id="findNext" data-l10n-id="find_next">></button>
|
||||||
|
<input type="checkbox" id="findHighlightAll">
|
||||||
|
<label for="findHighlightAll" data-l10n-id="find_highlight">Highlight all</label>
|
||||||
|
<input type="checkbox" id="findMatchCase">
|
||||||
|
<label for="findMatchCase" data-l10n-id="find_match_case_label">Match case</label>
|
||||||
|
<span id="findMsg"></span>
|
||||||
|
</div>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<div id="toolbarContainer">
|
<div id="toolbarContainer">
|
||||||
|
|
||||||
<div id="toolbarViewer">
|
<div id="toolbarViewer">
|
||||||
<div id="toolbarViewerLeft">
|
<div id="toolbarViewerLeft">
|
||||||
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="4" data-l10n-id="toggle_slider">
|
<button id="sidebarToggle" class="toolbarButton" title="Toggle Sidebar" tabindex="3" data-l10n-id="toggle_slider">
|
||||||
<span data-l10n-id="toggle_slider_label">Toggle Sidebar</span>
|
<span data-l10n-id="toggle_slider_label">Toggle Sidebar</span>
|
||||||
</button>
|
</button>
|
||||||
<div class="toolbarButtonSpacer"></div>
|
<div class="toolbarButtonSpacer"></div>
|
||||||
|
<!--#if !MOZCENTRAL-->
|
||||||
|
<button id="viewFind" class="toolbarButton group" title="Find in Document" tabindex="4" data-l10n-id="find">
|
||||||
|
<span data-l10n-id="find_label">Find</span>
|
||||||
|
</button>
|
||||||
|
<!--#endif-->
|
||||||
<div class="splitToolbarButton">
|
<div class="splitToolbarButton">
|
||||||
<button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="5" data-l10n-id="previous">
|
<button class="toolbarButton pageUp" title="Previous Page" id="previous" tabindex="5" data-l10n-id="previous">
|
||||||
<span data-l10n-id="previous_label">Previous</span>
|
<span data-l10n-id="previous_label">Previous</span>
|
||||||
|
730
web/viewer.js
730
web/viewer.js
@ -34,6 +34,12 @@ var RenderingStates = {
|
|||||||
PAUSED: 2,
|
PAUSED: 2,
|
||||||
FINISHED: 3
|
FINISHED: 3
|
||||||
};
|
};
|
||||||
|
var FindStates = {
|
||||||
|
FIND_FOUND: 0,
|
||||||
|
FIND_NOTFOUND: 1,
|
||||||
|
FIND_WRAPPED: 2,
|
||||||
|
FIND_PENDING: 3
|
||||||
|
};
|
||||||
|
|
||||||
//#if (GENERIC || CHROME)
|
//#if (GENERIC || CHROME)
|
||||||
//PDFJS.workerSrc = '../build/pdf.js';
|
//PDFJS.workerSrc = '../build/pdf.js';
|
||||||
@ -222,6 +228,374 @@ var Settings = (function SettingsClosure() {
|
|||||||
var cache = new Cache(kCacheSize);
|
var cache = new Cache(kCacheSize);
|
||||||
var currentPageNumber = 1;
|
var currentPageNumber = 1;
|
||||||
|
|
||||||
|
var PDFFindController = {
|
||||||
|
startedTextExtraction: false,
|
||||||
|
|
||||||
|
// If active, find results 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.handleEvent = this.handleEvent.bind(this);
|
||||||
|
|
||||||
|
for (var i = 0; i < events.length; i++) {
|
||||||
|
window.addEventListener(events[i], this.handleEvent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
calcFindMatch: function(pageContent) {
|
||||||
|
var query = this.state.query;
|
||||||
|
var caseSensitive = this.state.caseSensitive;
|
||||||
|
var queryLen = query.length;
|
||||||
|
|
||||||
|
if (queryLen === 0)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
if (!caseSensitive) {
|
||||||
|
pageContent = pageContent.toLowerCase();
|
||||||
|
query = query.toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// Build the find 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);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleEvent: 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 (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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page.textLayer) {
|
||||||
|
page.textLayer.updateMatches();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
this.updateUIState(FindStates.FIND_PENDING);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (!firstMatch || !this.state.query) {
|
||||||
|
this.updateUIState(FindStates.FIND_FOUND);
|
||||||
|
} else {
|
||||||
|
this.updateUIState(FindStates.FIND_NOTFOUND);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If there is NO selection, then there is no match at all -> no sense to
|
||||||
|
// handle previous/next action.
|
||||||
|
if (this.selected.pageIdx === -1) {
|
||||||
|
this.updateUIState(FindStates.FIND_NOTFOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle findAgain case.
|
||||||
|
var previous = this.state.findPrevious;
|
||||||
|
var sPageIdx = this.selected.pageIdx;
|
||||||
|
var sMatchIdx = this.selected.matchIdx;
|
||||||
|
var findState = FindStates.FIND_FOUND;
|
||||||
|
|
||||||
|
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;
|
||||||
|
findState = FindStates.FIND_WRAPPED;
|
||||||
|
} else if (this.selected.pageIdx > sPageIdx) {
|
||||||
|
findState = FindStates.FIND_WRAPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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 first match on the page.
|
||||||
|
if (this.selected.pageIdx === sPageIdx) {
|
||||||
|
this.selected.matchIdx = 0;
|
||||||
|
findState = FindStates.FIND_WRAPPED;
|
||||||
|
} else if (this.selected.pageIdx < sPageIdx) {
|
||||||
|
findState = FindStates.FIND_WRAPPED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateUIState(findState, previous);
|
||||||
|
this.updatePage(sPageIdx, sPageIdx === this.selected.pageIdx);
|
||||||
|
if (sPageIdx !== this.selected.pageIdx) {
|
||||||
|
this.updatePage(this.selected.pageIdx, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
updateUIState: function(state, previous) {
|
||||||
|
// TODO: Update the firefox find bar or update the html findbar.
|
||||||
|
PDFFindBar.updateUIState(state, previous);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var PDFFindBar = {
|
||||||
|
// TODO: Enable the FindBar *AFTER* the pagesPromise in the load function
|
||||||
|
// got resolved
|
||||||
|
|
||||||
|
opened: false,
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
this.bar = document.getElementById('findbar');
|
||||||
|
this.toggleButton = document.getElementById('viewFind');
|
||||||
|
this.findField = document.getElementById('findInput');
|
||||||
|
this.highlightAll = document.getElementById('findHighlightAll');
|
||||||
|
this.caseSensitive = document.getElementById('findMatchCase');
|
||||||
|
this.findMsg = document.getElementById('findMsg');
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
this.toggleButton.addEventListener('click', function() {
|
||||||
|
self.toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.findField.addEventListener('input', function() {
|
||||||
|
self.dispatchEvent('');
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: Add keybindings CMD-G etc. to go to prev/
|
||||||
|
// next match when the findField is selected.
|
||||||
|
|
||||||
|
this.findField.addEventListener('keydown', function(evt) {
|
||||||
|
switch (evt.keyCode) {
|
||||||
|
case 13: // Enter
|
||||||
|
self.dispatchEvent('again', evt.shiftKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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(state, previous) {
|
||||||
|
var notFound = false;
|
||||||
|
var findMsg = '';
|
||||||
|
var status = 'pending';
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case FindStates.FIND_FOUND:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FindStates.FIND_NOTFOUND:
|
||||||
|
findMsg = mozL10n.get('find_not_found', null, 'Phrase not found');
|
||||||
|
notFound = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FindStates.FIND_WRAPPED:
|
||||||
|
if (previous) {
|
||||||
|
findMsg = mozL10n.get('find_wrapped_to_bottom', null,
|
||||||
|
'Reached end of page, continued from bottom');
|
||||||
|
} else {
|
||||||
|
findMsg = mozL10n.get('find_wrapped_to_top', null,
|
||||||
|
'Reached end of page, continued from top');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notFound) {
|
||||||
|
this.findField.classList.add('notFound');
|
||||||
|
} else {
|
||||||
|
this.findField.classList.remove('notFound');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.findMsg.textContent = findMsg;
|
||||||
|
},
|
||||||
|
|
||||||
|
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 = {
|
var PDFView = {
|
||||||
pages: [],
|
pages: [],
|
||||||
thumbnails: [],
|
thumbnails: [],
|
||||||
@ -256,6 +630,9 @@ var PDFView = {
|
|||||||
this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
|
this.watchScroll(thumbnailContainer, this.thumbnailViewScroll,
|
||||||
this.renderHighestPriority.bind(this));
|
this.renderHighestPriority.bind(this));
|
||||||
|
|
||||||
|
PDFFindBar.initialize();
|
||||||
|
PDFFindController.initialize();
|
||||||
|
|
||||||
this.initialized = true;
|
this.initialized = true;
|
||||||
container.addEventListener('scroll', function() {
|
container.addEventListener('scroll', function() {
|
||||||
self.lastScroll = Date.now();
|
self.lastScroll = Date.now();
|
||||||
@ -742,6 +1119,9 @@ var PDFView = {
|
|||||||
thumbnails.push(thumbnailView);
|
thumbnails.push(thumbnailView);
|
||||||
var pageRef = page.ref;
|
var pageRef = page.ref;
|
||||||
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
pagesRefMap[pageRef.num + ' ' + pageRef.gen + ' R'] = i;
|
||||||
|
|
||||||
|
// Trigger text extraction. TODO: Make this happen lasyliy if needed.
|
||||||
|
PDFFindController.extractText();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.pagesRefMap = pagesRefMap;
|
self.pagesRefMap = pagesRefMap;
|
||||||
@ -896,72 +1276,6 @@ var PDFView = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
search: function pdfViewStartSearch() {
|
|
||||||
// Limit this function to run every <SEARCH_TIMEOUT>ms.
|
|
||||||
var SEARCH_TIMEOUT = 250;
|
|
||||||
var lastSearch = this.lastSearch;
|
|
||||||
var now = Date.now();
|
|
||||||
if (lastSearch && (now - lastSearch) < SEARCH_TIMEOUT) {
|
|
||||||
if (!this.searchTimer) {
|
|
||||||
this.searchTimer = setTimeout(function resumeSearch() {
|
|
||||||
PDFView.search();
|
|
||||||
},
|
|
||||||
SEARCH_TIMEOUT - (now - lastSearch)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.searchTimer = null;
|
|
||||||
this.lastSearch = now;
|
|
||||||
|
|
||||||
function bindLink(link, pageNumber) {
|
|
||||||
link.href = '#' + pageNumber;
|
|
||||||
link.onclick = function searchBindLink() {
|
|
||||||
PDFView.page = pageNumber;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var searchResults = document.getElementById('searchResults');
|
|
||||||
|
|
||||||
var searchTermsInput = document.getElementById('searchTermsInput');
|
|
||||||
searchResults.removeAttribute('hidden');
|
|
||||||
searchResults.textContent = '';
|
|
||||||
|
|
||||||
var terms = searchTermsInput.value;
|
|
||||||
|
|
||||||
if (!terms)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// simple search: removing spaces and hyphens, then scanning every
|
|
||||||
terms = terms.replace(/\s-/g, '').toLowerCase();
|
|
||||||
var index = PDFView.pageText;
|
|
||||||
var pageFound = false;
|
|
||||||
for (var i = 0, ii = index.length; i < ii; i++) {
|
|
||||||
var pageText = index[i].replace(/\s-/g, '').toLowerCase();
|
|
||||||
var j = pageText.indexOf(terms);
|
|
||||||
if (j < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var pageNumber = i + 1;
|
|
||||||
var textSample = index[i].substr(j, 50);
|
|
||||||
var link = document.createElement('a');
|
|
||||||
bindLink(link, pageNumber);
|
|
||||||
link.textContent = 'Page ' + pageNumber + ': ' + textSample;
|
|
||||||
searchResults.appendChild(link);
|
|
||||||
|
|
||||||
pageFound = true;
|
|
||||||
}
|
|
||||||
if (!pageFound) {
|
|
||||||
searchResults.textContent = '';
|
|
||||||
var noResults = document.createElement('div');
|
|
||||||
noResults.classList.add('noResults');
|
|
||||||
noResults.textContent = mozL10n.get('search_terms_not_found', null,
|
|
||||||
'(Not found)');
|
|
||||||
searchResults.appendChild(noResults);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
setHash: function pdfViewSetHash(hash) {
|
setHash: function pdfViewSetHash(hash) {
|
||||||
if (!hash)
|
if (!hash)
|
||||||
return;
|
return;
|
||||||
@ -1003,20 +1317,16 @@ var PDFView = {
|
|||||||
switchSidebarView: function pdfViewSwitchSidebarView(view) {
|
switchSidebarView: function pdfViewSwitchSidebarView(view) {
|
||||||
var thumbsView = document.getElementById('thumbnailView');
|
var thumbsView = document.getElementById('thumbnailView');
|
||||||
var outlineView = document.getElementById('outlineView');
|
var outlineView = document.getElementById('outlineView');
|
||||||
var searchView = document.getElementById('searchView');
|
|
||||||
|
|
||||||
var thumbsButton = document.getElementById('viewThumbnail');
|
var thumbsButton = document.getElementById('viewThumbnail');
|
||||||
var outlineButton = document.getElementById('viewOutline');
|
var outlineButton = document.getElementById('viewOutline');
|
||||||
var searchButton = document.getElementById('viewSearch');
|
|
||||||
|
|
||||||
switch (view) {
|
switch (view) {
|
||||||
case 'thumbs':
|
case 'thumbs':
|
||||||
thumbsButton.classList.add('toggled');
|
thumbsButton.classList.add('toggled');
|
||||||
outlineButton.classList.remove('toggled');
|
outlineButton.classList.remove('toggled');
|
||||||
searchButton.classList.remove('toggled');
|
|
||||||
thumbsView.classList.remove('hidden');
|
thumbsView.classList.remove('hidden');
|
||||||
outlineView.classList.add('hidden');
|
outlineView.classList.add('hidden');
|
||||||
searchView.classList.add('hidden');
|
|
||||||
|
|
||||||
PDFView.renderHighestPriority();
|
PDFView.renderHighestPriority();
|
||||||
break;
|
break;
|
||||||
@ -1024,49 +1334,15 @@ var PDFView = {
|
|||||||
case 'outline':
|
case 'outline':
|
||||||
thumbsButton.classList.remove('toggled');
|
thumbsButton.classList.remove('toggled');
|
||||||
outlineButton.classList.add('toggled');
|
outlineButton.classList.add('toggled');
|
||||||
searchButton.classList.remove('toggled');
|
|
||||||
thumbsView.classList.add('hidden');
|
thumbsView.classList.add('hidden');
|
||||||
outlineView.classList.remove('hidden');
|
outlineView.classList.remove('hidden');
|
||||||
searchView.classList.add('hidden');
|
|
||||||
|
|
||||||
if (outlineButton.getAttribute('disabled'))
|
if (outlineButton.getAttribute('disabled'))
|
||||||
return;
|
return;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'search':
|
|
||||||
thumbsButton.classList.remove('toggled');
|
|
||||||
outlineButton.classList.remove('toggled');
|
|
||||||
searchButton.classList.add('toggled');
|
|
||||||
thumbsView.classList.add('hidden');
|
|
||||||
outlineView.classList.add('hidden');
|
|
||||||
searchView.classList.remove('hidden');
|
|
||||||
|
|
||||||
var searchTermsInput = document.getElementById('searchTermsInput');
|
|
||||||
searchTermsInput.focus();
|
|
||||||
// Start text extraction as soon as the search gets displayed.
|
|
||||||
this.extractText();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
extractText: function() {
|
|
||||||
if (this.startedTextExtraction)
|
|
||||||
return;
|
|
||||||
this.startedTextExtraction = true;
|
|
||||||
var self = this;
|
|
||||||
function extractPageText(pageIndex) {
|
|
||||||
self.pages[pageIndex].pdfPage.getTextContent().then(
|
|
||||||
function textContentResolved(textContent) {
|
|
||||||
self.pageText[pageIndex] = textContent.join('');
|
|
||||||
self.search();
|
|
||||||
if ((pageIndex + 1) < self.pages.length)
|
|
||||||
extractPageText(pageIndex + 1);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
extractPageText(0);
|
|
||||||
},
|
|
||||||
|
|
||||||
getVisiblePages: function pdfViewGetVisiblePages() {
|
getVisiblePages: function pdfViewGetVisiblePages() {
|
||||||
return this.getVisibleElements(this.container,
|
return this.getVisibleElements(this.container,
|
||||||
this.pages, true);
|
this.pages, true);
|
||||||
@ -1246,6 +1522,7 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||||||
this.resume = null;
|
this.resume = null;
|
||||||
|
|
||||||
this.textContent = null;
|
this.textContent = null;
|
||||||
|
this.textLayer = null;
|
||||||
|
|
||||||
var anchor = document.createElement('a');
|
var anchor = document.createElement('a');
|
||||||
anchor.name = '' + this.id;
|
anchor.name = '' + this.id;
|
||||||
@ -1492,7 +1769,8 @@ var PageView = function pageView(container, pdfPage, id, scale,
|
|||||||
textLayerDiv.className = 'textLayer';
|
textLayerDiv.className = 'textLayer';
|
||||||
div.appendChild(textLayerDiv);
|
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;
|
var scale = this.scale, viewport = this.viewport;
|
||||||
canvas.width = viewport.width;
|
canvas.width = viewport.width;
|
||||||
@ -1851,21 +2129,25 @@ var CustomStyle = (function CustomStyleClosure() {
|
|||||||
return CustomStyle;
|
return CustomStyle;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
var TextLayerBuilder = function textLayerBuilder(textLayerDiv, pageIdx) {
|
||||||
var textLayerFrag = document.createDocumentFragment();
|
var textLayerFrag = document.createDocumentFragment();
|
||||||
|
|
||||||
this.textLayerDiv = textLayerDiv;
|
this.textLayerDiv = textLayerDiv;
|
||||||
this.layoutDone = false;
|
this.layoutDone = false;
|
||||||
this.divContentDone = false;
|
this.divContentDone = false;
|
||||||
|
this.pageIdx = pageIdx;
|
||||||
|
this.matches = [];
|
||||||
|
|
||||||
this.beginLayout = function textLayerBuilderBeginLayout() {
|
this.beginLayout = function textLayerBuilderBeginLayout() {
|
||||||
this.textDivs = [];
|
this.textDivs = [];
|
||||||
this.textLayerQueue = [];
|
this.textLayerQueue = [];
|
||||||
|
this.renderingDone = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.endLayout = function textLayerBuilderEndLayout() {
|
this.endLayout = function textLayerBuilderEndLayout() {
|
||||||
this.layoutDone = true;
|
this.layoutDone = true;
|
||||||
this.insertDivContent();
|
this.insertDivContent();
|
||||||
},
|
};
|
||||||
|
|
||||||
this.renderLayer = function textLayerBuilderRenderLayer() {
|
this.renderLayer = function textLayerBuilderRenderLayer() {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -1879,8 +2161,11 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
|||||||
if (textDivs.length > 100000)
|
if (textDivs.length > 100000)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (textDivs.length > 0) {
|
var i = textDivs.length;
|
||||||
var textDiv = textDivs.shift();
|
|
||||||
|
while (i !== 0) {
|
||||||
|
i--;
|
||||||
|
var textDiv = textDivs[i];
|
||||||
textLayerFrag.appendChild(textDiv);
|
textLayerFrag.appendChild(textDiv);
|
||||||
|
|
||||||
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
ctx.font = textDiv.style.fontSize + ' ' + textDiv.style.fontFamily;
|
||||||
@ -1892,9 +2177,14 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
|||||||
CustomStyle.setProp('transform' , textDiv,
|
CustomStyle.setProp('transform' , textDiv,
|
||||||
'scale(' + textScale + ', 1)');
|
'scale(' + textScale + ', 1)');
|
||||||
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
CustomStyle.setProp('transformOrigin' , textDiv, '0% 0%');
|
||||||
|
|
||||||
|
textLayerDiv.appendChild(textDiv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.renderingDone = true;
|
||||||
|
this.updateMatches();
|
||||||
|
|
||||||
textLayerDiv.appendChild(textLayerFrag);
|
textLayerDiv.appendChild(textLayerFrag);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1961,6 +2251,201 @@ var TextLayerBuilder = function textLayerBuilder(textLayerDiv) {
|
|||||||
this.textContent = textContent;
|
this.textContent = textContent;
|
||||||
this.insertDivContent();
|
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) {
|
||||||
|
// Early exit if there is nothing to render.
|
||||||
|
if (matches.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 highlightAll = PDFFindController.state.highlightAll;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
var i0 = selectedMatchIdx, i1 = i0 + 1, i;
|
||||||
|
|
||||||
|
if (highlightAll) {
|
||||||
|
i0 = 0;
|
||||||
|
i1 = matches.length;
|
||||||
|
} else if (!isSelectedPage) {
|
||||||
|
// Not highlighting all and this isn't the selected page, so do nothing.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = i0; i < i1; 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;
|
||||||
|
|
||||||
|
// Clear out all current matches.
|
||||||
|
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 = textDivs[n];
|
||||||
|
div.textContent = bidiTexts[n].str;
|
||||||
|
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) {
|
document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
||||||
@ -2025,8 +2510,8 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
|||||||
|
|
||||||
//#if !(FIREFOX || MOZCENTRAL)
|
//#if !(FIREFOX || MOZCENTRAL)
|
||||||
//#else
|
//#else
|
||||||
//if (FirefoxCom.requestSync('searchEnabled')) {
|
//if (FirefoxCom.requestSync('findEnabled')) {
|
||||||
// document.querySelector('#viewSearch').classList.remove('hidden');
|
// document.querySelector('#viewFind').classList.remove('hidden');
|
||||||
//}
|
//}
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
@ -2076,16 +2561,6 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
|||||||
PDFView.switchSidebarView('outline');
|
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',
|
document.getElementById('previous').addEventListener('click',
|
||||||
function() {
|
function() {
|
||||||
PDFView.page--;
|
PDFView.page--;
|
||||||
@ -2126,13 +2601,6 @@ document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
|
|||||||
PDFView.download();
|
PDFView.download();
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('searchTermsInput').addEventListener('keydown',
|
|
||||||
function(event) {
|
|
||||||
if (event.keyCode == 13) {
|
|
||||||
PDFView.search();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('pageNumber').addEventListener('change',
|
document.getElementById('pageNumber').addEventListener('change',
|
||||||
function() {
|
function() {
|
||||||
PDFView.page = this.value;
|
PDFView.page = this.value;
|
||||||
@ -2350,6 +2818,12 @@ window.addEventListener('keydown', function keydown(evt) {
|
|||||||
// control is selected or not.
|
// control is selected or not.
|
||||||
if (cmd == 1 || cmd == 8) { // either CTRL or META key.
|
if (cmd == 1 || cmd == 8) { // either CTRL or META key.
|
||||||
switch (evt.keyCode) {
|
switch (evt.keyCode) {
|
||||||
|
//#if !MOZCENTRAL
|
||||||
|
case 70:
|
||||||
|
PDFFindBar.toggle();
|
||||||
|
handled = true;
|
||||||
|
break;
|
||||||
|
//#endif
|
||||||
case 61: // FF/Mac '='
|
case 61: // FF/Mac '='
|
||||||
case 107: // FF '+' and '='
|
case 107: // FF '+' and '='
|
||||||
case 187: // Chrome '+'
|
case 187: // Chrome '+'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user