import CompilePannelTemplate from "./templates/thumb.art";
import compileThumbTemplate from "./templates/thumb-item.art";
import * as UIExtension from "UIExtension";
import _debounce from "lodash/debounce";
const __ = UIExtension.__;
const $ = UIExtension.vendors.jQuery;
const PDFDocPermission = UIExtension.PDFViewCtrl.Consts.PDFDocPermission;
const Events = UIExtension.PDFViewCtrl.ViewerEvents;
import "./style/thumb.scss";
import Dragable from '../../src/shared/Dragable.js';
import { htmlCharacter2Entity } from "../../src/shared/html-util";
import DragFileInsert from './dragFileInsert';
import {
THUMBNAIL_PAGE_BASIS_WIDTH,
THUMBNAIL_PAGE_BASIS_HEIGHT,
adjustContainerFlexBox,
resetContainerStyle,
resetScale,
showScaleContextmenu
} from "./contextmenu/thumbScale";
import { isPageLabelSetting } from "../../src/shared/feature-common/formatPageLabel";
import { ThumbnailZoomService } from './zoom/ThumbnailZoomService';
import { DebounceAsyncTaskExecutor } from './core';
const THUMB_BORDER_WIDTH = 1;
const RECT_BORDER_WIDTH = 2;
const {
PDFViewCtrl: {
BrowserInfo: { isSafari },
DeviceInfo: {
},
shared: {
attachContextMenuEvent
}
}
} = UIExtension;
export default class ThumbUIComponent extends UIExtension.components
return "thumbnail-panel";
}
static inject() {
return {
zoomService: ThumbnailZoomService,
};
}
constructor(...props) {
super(...props);
this.updateVisiblePages = _debounce(this.updateVisiblePages.bind(this), 100);
this.evTnRectDown = null;
this.evDocMove = null;
this.evDocUp = null;
this.moving = false;
this.resizing = false;
this.cachePageIndex = -1;
this.prevPos = {x: 0, y: 0};
}
allInjected() {
const executor = new DebounceAsyncTaskExecutor()
this.zoomService.onScaleChanged((scaleRatio, isMin, isMax, isSmall) => {
executor.exec(() => {
return this.getPDFUI().getPDFViewer().then(pdfViewer => {
if(!pdfViewer.getCurrentPDFDoc()) {
return;
}
return this._updateOnScaleChanged(scaleRatio, isSmall);
});
});
}),
() => executor.cancel()
)
}
_updateOnScaleChanged(scaleRatio, isSmall) {
const { $thumbImageContainer, $thumbImageContainerBox} = this;
const thumbImageContainerBox = $thumbImageContainerBox.get(0);
const thumbImageContainer = $thumbImageContainer.get(0);
thumbImageContainer.classList.toggle('small-size', isSmall);
const pageWidth = THUMBNAIL_PAGE_BASIS_WIDTH * scaleRatio;
const pageHeight = THUMBNAIL_PAGE_BASIS_HEIGHT * scaleRatio;
const pages = thumbImageContainer.querySelectorAll('.fv__thumb-page');
pages.forEach(el => {
el.style.cssText += `
width: ${pageWidth}px;
height: ${pageHeight}px
`;
});
const containerBoxWidth = thumbImageContainerBox.getBoundingClientRect().width;
const containerWidth = thumbImageContainer.getBoundingClientRect().width;
if (pageWidth < containerWidth && containerWidth > containerBoxWidth) {
$thumbImageContainer.css({ width: Math.max(pageWidth, containerBoxWidth) });
} else if (containerWidth < pageWidth) {
$thumbImageContainer.css({ width: pageWidth });
} else {
$thumbImageContainer.css({ width: 'auto' });
}
return this.updateVisiblePages();
}
createDOMElement() {
return document.createElement("div");
}
return this.$html.find(".fv__thumb-image-container")[0];
}
super.render();
this.element.classList.add('fv__ui-thumbnail-panel-body');
$element[0].innerHTML = CompilePannelTemplate();
this.$thumbImageContainerBox = $element.find(
".fv__thumb-image-container-box"
);
this.$thumbImageContainer = $element.find(".fv__thumb-image-container");
this.$html = $element;
}
mounted() {
super.mounted();
const isCollaborationMode = this.pdfUI.customs && this.pdfUI.customs.isCollaborationMode();
this.contextmenuSwitch = isCollaborationMode ? 'off' : 'on';
this.$thumbImageContainerBox.scroll(e => {
this.updateVisiblePages();
});
this.addDragEvent();
if (
navigator &&
navigator.userAgent &&
navigator.userAgent.indexOf("Firefox") > -1
) {
this.element.addEventListener("drop", e => {
e.preventDefault();
e.stopPropagation();
});
}
const modifyPermission = UIExtension.PDFViewCtrl.Consts.PDFDocPermission.ModifyDocument;
const contextmenu = this.
getRoot().getComponentByName(
"fv--thumbnail-contextmenu");
if (contextmenu) {
const assemblePermission = modifyPermission + UIExtension.PDFViewCtrl.Consts.PDFDocPermission.Assemble;
const contextMenuItemCopy = contextmenu.getComponentByName("contextmenu-item-thumbnail-copy");
const contextMenuItemPaste = contextmenu.getComponentByName("contextmenu-item-thumbnail-paste");
const contextMenuItemDelete = contextmenu.getComponentByName("contextmenu-item-thumbnail-delete");
const contextMenuPageReverse = contextmenu.getComponentByName("organize-tab-page-reverse");
const contextMenuItemExtract = contextmenu.getComponentByName("contextmenu-item-thumbnail-extract");
const contextMenuItemSplit = contextmenu.getComponentByName("contextmenu-item-thumbnail-split");
const contextMenuItemRotate = contextmenu.getComponentByName("contextmenu-item-thumbnail-rotate");
const contextMenuItemRotateLeft = contextmenu.getComponentByName("contextmenu-item-thumbnail-rotate-left");
const contextMenuItemRotateRight = contextmenu.getComponentByName("contextmenu-item-thumbnail-rotate-right");
const contextmenuItemThumbnailMove = contextmenu.getComponentByName('contextmenu-item-thumbnail-move');
const contextMenuItemEnlarge = contextmenu.getComponentByName('contextmenu-item-thumbnail-enlarge');
const contextMenuItemReduce = contextmenu.getComponentByName('contextmenu-item-thumbnail-reduce');
const contextmenuItemThumbnailSwap = contextmenu.getComponentByName('contextmenu-item-thumbnail-swap');
const contextmenuItemThumbnailReplace = contextmenu.getComponentByName('contextmenu-item-thumbnail-replace');
const contextmenuItemThumbnailCrop = contextmenu.getComponentByName('contextmenu-item-thumbnail-crop');
const contextmenuItemThumbnailDuplicate = contextmenu.getComponentByName('contextmenu-item-thumbnail-duplicate');
const contextmenuItemEmbed = contextmenu.getComponentByName('contextmenu-item-thumbnail-embed');
const contextmenuItemRemoveEmbedded = contextmenu.getComponentByName('contextmenu-item-thumbnail-remove-embedded');
const contextmenuItemFormatNumbering = contextmenu.getComponentByName('contextmenu-item-thumbnail-format-numbering');
const contextmenuItemSepReversePage = contextmenu.getComponentByName('contextmenu-item-sep-reverse-page');
const contextmenuItemAddBlankPage = contextmenu.getComponentByName('contextmenu-item-thumbnail-add-blank-page');
const contextmenuItemPageTransitions = contextmenu.getComponentByName('contextmenu-item-thumbnail-pageTransitions');
const pageProperties = contextmenu.getComponentByName('contextmenu-item-thumbnail-properties');
if (this.pdfUI.pdfViewer.currentPDFDoc.viewAutoScrolling) {
contextmenu.disable();
return;
}
contextmenu.enable();
.then(docRender => {
const permission = docRender.getUserPermission().getValue();
const isXFA = docRender.doc.isXFA();
const contextmenuItemInsertPage = document.querySelector('#contextmenu-item-insert-page');
if (permission & modifyPermission) {
contextMenuItemCopy && contextMenuItemCopy.enable();
contextMenuItemPaste && contextMenuItemPaste.enable();
contextMenuPageReverse && contextMenuPageReverse.enable();
contextMenuItemExtract && contextMenuItemExtract.enable();
contextMenuItemSplit && contextMenuItemSplit.enable();
contextmenuItemThumbnailMove && contextmenuItemThumbnailMove.enable();
contextmenuItemThumbnailSwap && contextmenuItemThumbnailSwap.enable();
contextmenuItemThumbnailCrop && contextmenuItemThumbnailCrop.enable();
contextmenuItemThumbnailDuplicate && contextmenuItemThumbnailDuplicate.enable();
contextmenuItemThumbnailReplace && contextmenuItemThumbnailReplace.enable();
contextmenuItemEmbed && contextmenuItemEmbed.enable();
contextmenuItemRemoveEmbedded && contextmenuItemRemoveEmbedded.enable();
contextmenuItemFormatNumbering && contextmenuItemFormatNumbering.enable();
contextmenuItemInsertPage && contextmenuItemInsertPage.classList.remove("disabled");
contextmenuItemPageTransitions && contextmenuItemPageTransitions.enable();
pageProperties && pageProperties.enable();
if (this.controller.recordPagesToClipboard) {
contextMenuItemPaste && contextMenuItemPaste.enable();
} else {
contextMenuItemPaste && contextMenuItemPaste.disable();
}
} else {
contextMenuItemCopy && contextMenuItemCopy.disable();
contextMenuItemPaste && contextMenuItemPaste.disable();
contextMenuPageReverse && contextMenuPageReverse.disable();
contextMenuItemExtract && contextMenuItemExtract.disable();
contextMenuItemSplit && contextMenuItemSplit.disable();
contextmenuItemThumbnailMove && contextmenuItemThumbnailMove.disable();
contextmenuItemThumbnailSwap && contextmenuItemThumbnailSwap.disable();
contextmenuItemThumbnailCrop && contextmenuItemThumbnailCrop.disable();
contextmenuItemThumbnailDuplicate && contextmenuItemThumbnailDuplicate.disable();
contextmenuItemThumbnailReplace && contextmenuItemThumbnailReplace.disable();
contextmenuItemEmbed && contextmenuItemEmbed.disable();
contextmenuItemRemoveEmbedded && contextmenuItemRemoveEmbedded.disable();
contextmenuItemFormatNumbering && contextmenuItemFormatNumbering.disable();
contextmenuItemInsertPage && contextmenuItemInsertPage.classList.add("disabled");
contextmenuItemPageTransitions && contextmenuItemPageTransitions.disable();
pageProperties && pageProperties.disable();
}
if (permission & assemblePermission) {
contextMenuItemDelete && contextMenuItemDelete.enable();
contextMenuItemRotate && contextMenuItemRotate.enable();
contextMenuItemRotateLeft && contextMenuItemRotateLeft.enable();
contextMenuItemRotateRight && contextMenuItemRotateRight.enable();
contextmenuItemAddBlankPage && contextmenuItemAddBlankPage.enable();
} else {
contextMenuItemDelete && contextMenuItemDelete.disable();
contextMenuItemRotate && contextMenuItemRotate.disable();
contextMenuItemRotateLeft && contextMenuItemRotateLeft.disable();
contextMenuItemRotateRight && contextMenuItemRotateRight.disable();
contextmenuItemAddBlankPage && contextmenuItemAddBlankPage.disable();
}
if (this.$pages.length <= 1) {
contextMenuItemDelete && contextMenuItemDelete.disable();
contextmenuItemThumbnailMove && contextmenuItemThumbnailMove.disable();
contextmenuItemThumbnailSwap && contextmenuItemThumbnailSwap.disable();
}
isXFA.then((res) => {
if(res) {
contextMenuItemRotate && contextMenuItemRotate.disable();
contextMenuItemRotateLeft && contextMenuItemRotateLeft.disable();
contextMenuItemRotateRight && contextMenuItemRotateRight.disable();
contextMenuItemDelete && contextMenuItemDelete.disable();
contextmenuItemAddBlankPage && contextmenuItemAddBlankPage.disable()
contextmenuItemThumbnailMove && contextmenuItemThumbnailMove.disable();
contextmenuItemThumbnailSwap && contextmenuItemThumbnailSwap.disable();
contextMenuItemSplit && contextMenuItemSplit.disable();
contextmenuItemThumbnailCrop && contextmenuItemThumbnailCrop.disable();
contextmenuItemThumbnailDuplicate && contextmenuItemThumbnailDuplicate.disable();
}
})
if (!this.checkAddonInstance('MovePagesUIXAddon') || this.controller.isStaticXFA) {
contextmenuItemThumbnailMove && contextmenuItemThumbnailMove.disable();
}
const isProtectedView = localStorage.getItem('SECURITY_PROTECTED_VIEW') === 'all' ? true:false;
const arr = [contextMenuItemCopy,contextMenuItemPaste,contextMenuItemDelete,contextMenuItemExtract,contextMenuItemSplit,contextMenuItemRotate,contextMenuItemRotateLeft,contextMenuItemRotateRight,contextmenuItemThumbnailMove,contextmenuItemThumbnailSwap,contextmenuItemThumbnailReplace,contextmenuItemThumbnailCrop,contextmenuItemThumbnailDuplicate,contextmenuItemEmbed,contextmenuItemRemoveEmbedded,contextmenuItemFormatNumbering,contextMenuPageReverse, contextmenuItemAddBlankPage, contextmenuItemPageTransitions];
if(isProtectedView){
arr.forEach(
m=>
m &&
m.hide());
contextmenuItemInsertPage && (contextmenuItemInsertPage.style.display='none');
setTimeout(()=>{
contextMenuPageReverse && contextMenuPageReverse.hide();
contextmenuItemSepReversePage && contextmenuItemSepReversePage.hide();
})
}else{
arr.forEach(
m=>
m &&
m.show());
contextmenuItemInsertPage && (contextmenuItemInsertPage.style.display='block');
}
return docRender.doc.getPasswordType();
}).then(type => {
.then((docRender) => {
const permission = docRender.getUserPermission().getValue();
if (type === 1 && permission > 0) {
contextMenuItemExtract && contextMenuItemExtract.disable();
contextMenuItemSplit && contextMenuItemSplit.disable();
} else {
contextMenuItemExtract && contextMenuItemExtract.enable();
contextMenuItemSplit && contextMenuItemSplit.enable();
}
})
})
});
});
}
const detachContextmenu = attachContextMenuEvent(
this.element,
e => {
const ePageThumb = e.target.closest("[data-page-index]");
if (!ePageThumb) {
if (showScaleContextmenu(this.
getRoot(), e)) {
e.preventDefault();
}
return;
}
const pageIndex = +ePageThumb.getAttribute("data-page-index");
const contextmenu = this.
getRoot().getComponentByName(
"fv--thumbnail-contextmenu"
);
if(this.contextmenuSwitch === 'off' || !contextmenu){return}
contextmenu.setCurrentTarget(pageIndex);
contextmenu.showAt(e.clientX, e.clientY);
e.preventDefault();
},
true,
);
this.$thumbImageContainerBox.on("mouseup", ".fv__thumb-page", e => {
if (e.button !== 0 && e.button !== 2) {
return;
}
const cnt = this.$thumbImageContainer.find(".fv__thumb-page").length;
if(cnt < 1) {
return;
}
let $pageThumb = $(e.currentTarget);
const pageIndex = $pageThumb.data("page-index");
const isCtrlKey = (isMacOS && e.metaKey) || (!isMacOS && e.ctrlKey);
if (isCtrlKey) {
if (e.button === 2) {
$pageThumb.addClass("fv__active");
} else {
$pageThumb.toggleClass("fv__active");
}
} else {
const isCurrentItemActive = this.$thumbImageContainer.find('.fv__thumb-page.fv__active[data-page-index="' + pageIndex + '"]').length > 0;
if (!(e.button === 2 && isCurrentItemActive)) {
this.$html.find(".fv__active").removeClass("fv__active");
}
$pageThumb.addClass("fv__active");
}
this.fromClickThumb = pageIndex;
this.doPageAction(this.previePageIndex, pageIndex);
this.previePageIndex = pageIndex;
this.
getPDFUI().
goToPage(pageIndex, 0, 0,
false);
(!this.resizing && !this.moving) && this.calcThumbnailRect(true, pageIndex);
});
this.$thumbImageContainerBox.off("mouseup");
});
const delKeyHandle = async (e) => {
const defaultDeleteBinderName = this.
getPDFUI().pdfViewer.keyboard.defaultDeleteBinderName;
if(!this.parent.isActive || defaultDeleteBinderName !== 'thumbUIComponent') {
return;
}
if(!docRender) {
return;
}
const permission = docRender.getUserPermission().getValue();
if (
!(
permission & PDFDocPermission.Assemble ||
permission & PDFDocPermission.ModifyDocument
)
) {
return;
}
const targetClassName = e.nativeEvent.target.className;
const modal = $('.fv__ui-layer-modal');
if((modal.length > 0 || targetClassName !== 'fv__thumb-image-container-box')) return;
const $pages = this.$pages;
const $activePages = this.$html.find(".fv__active");
if ($pages.length <= 1) {
this.
getPDFUI().
alert(
"thumbnail:removePageAlert", undefined, undefined,
'warning');
return;
}
if ($activePages.length >= $pages.length) {
this.
getPDFUI().alert(
"thumbnail:removePageAlert", undefined, undefined,
'warning');
return;
}
this.
getPDFUI().
confirm(
"thumbnail:removePageConfirm", undefined, undefined,
'prompt').then(async () => {
let ids = [];
$activePages.each((index, item) => {
ids.push($(item).data("page-index"));
});
if (ids.length > 0) {
ids = ids.sort(function(x, y) {
return y - x;
});
for (let i=0; i<ids.length; i++) {
await this.controller.deletePageByIndex(ids[i]);
await new Promise(resolve => setTimeout(resolve, 50));
}
const indexesRange = Array.from(ids).reverse().map((index) => [index, index]);
this.controller.currentPDFDoc.updatePageLabelsByAction('deletePages', [indexesRange]);
}
}, () => {});
};
});
}
dragFileInsert(data) {
this.pdfUI.customs.sendGAEvent({
category: 'Organize',
label: 'organize_tab',
action: 'insert_page_by_dragging',
eventKey: 'Insert page by dragging'
});
const isAccountExpired = this.pdfUI.customs.isAccountExpired();
if (isAccountExpired) {
this.dragable._removeClass(this.dragable.options.chosenClass, data.target);
return;
}
const dragFileInsert = DragFileInsert.getInstance({
component: this,
pdfUI: this.pdfUI
});
dragFileInsert.start(data);
}
enableDragAndDrop(enable) {
if (!this.dragable) return;
this.dragable.options.allowDrag = !!
enable;
}
async _checkAndGetLabels() {
const hasLabel = await this.controller.currentPDFDoc.checkDocHasPageLabel();
let labels = null;
if (hasLabel) {
labels = await this.controller.currentPDFDoc.getPageLabels();
}
return { hasLabel, labels };
}
async initPageItems(pageCount) {
const logicalPageNumChecked = isPageLabelSetting();
let hasLabel = false;
let labels = [];
if (logicalPageNumChecked) {
const labelsObj = await this._checkAndGetLabels();
hasLabel = labelsObj.hasLabel;
labels = labelsObj.labels;
}
let $oldPages = this.$pages;
if (!$oldPages || $oldPages.length == 0) {
let pageItems = "";
for (let i = 0; i < pageCount; i++) {
const label = logicalPageNumChecked && hasLabel ? htmlCharacter2Entity(labels[i]) : i + 1;
pageItems += compileThumbTemplate({
index: i, label });
}
this.$thumbImageContainer.append(pageItems);
} else {
this.$pages.find('.fv__thumb-page-container').addClass("loading");
let $canvases = this.$thumbImageContainer.find("canvas");
$canvases.each(index => $canvases[index].width = $canvases[index].width);
this.$thumbImageContainer.find(".fv__thumb-page-index").each((i, el) => {
if (i >= pageCount) {
return;
}
const label = logicalPageNumChecked && hasLabel ? htmlCharacter2Entity(labels[i]) : i + 1;
$(el).html(label);
});
let diffCount = pageCount - $canvases.length;
let index = 0;
if (diffCount < 0) {
while (index < -diffCount) {
$($oldPages.get($canvases.length - index - 1)).remove();
index++;
}
} else {
let pageItems = "";
for (let i = 0; i < diffCount; i++) {
const idx = $canvases.length + i;
const label = hasLabel ? htmlCharacter2Entity(labels[idx]) : idx + 1;
pageItems += compileThumbTemplate({
index: idx, label });
}
this.$thumbImageContainer.append(pageItems);
}
$oldPages.show();
}
this.$pages = this.$thumbImageContainer.find(".fv__thumb-page");
this.visiblePages = [];
this.initThumbnailRect();
}
initThumbnailRect() {
let rectTarget = null;
let startPos = { x: 0, y: 0, w: 0, h: 0 };
let elePos = { x: 0, y: 0 };
let eleRect = {};
let parentRect = {};
let thumbRect = {};
let $rects = this.$thumbImageContainer.find('.fv__thumb-view-rect');
!this.evTnRectDown && $rects.on('mousedown', this.evTnRectDown = ev => {
if (ev.target.className.indexOf('fv__thumb-view-rect') >= 0) {
ev.stopPropagation();
let target = ev.target;
eleRect = target.getBoundingClientRect();
parentRect = target.parentElement.getBoundingClientRect();
thumbRect = $(target.parentElement).find('.fv__thumb-image').get(0).getBoundingClientRect();
let mouseX = ev.clientX - eleRect.left;
let mouseY = ev.clientY - eleRect.top;
rectTarget = target;
startPos.x = ev.clientX;
startPos.y = ev.clientY;
startPos.w = parseInt(rectTarget.style.width || 0, 10);
startPos.h = parseInt(rectTarget.style.height || 0, 10);
if (mouseX > eleRect.width - 15 && mouseY > eleRect.height - 15) {
let $eleRect = this.$thumbImageContainer.find('.fv__thumb-page .fv__thumb-view-rect.fv__rect_active');
let $eleThumb = $eleRect.parent().find('.fv__thumb-image');
$eleRect.css('max-width', $eleThumb.outerWidth() + RECT_BORDER_WIDTH)
.css('max-height', $eleThumb.outerHeight() + RECT_BORDER_WIDTH);
this.resizing = true;
return false;
}
this.moving = true;
elePos.x = parseInt(rectTarget.style.left || 0, 10);
elePos.y = parseInt(rectTarget.style.top || 0, 10);
return false;
}
});
!this.evDocUp && $(document).
on(
'mouseup', this.evDocUp = ev => {
if (this.resizing || this.moving) {
let $eleRect = this.$thumbImageContainer.find('.fv__thumb-page .fv__thumb-view-rect.fv__rect_active');
$eleRect.css('max-width', '')
.css('max-height', '');
let isOnlyMoving = false;
ev.stopPropagation();
this.resizing = false;
if (this.moving && !this.resizing) isOnlyMoving = true;
this.rectZoomToPage(isOnlyMoving);
this.moving = false;
rectTarget = null;
}
});
!this.evDocMove && $(document).
on(
'mousemove', this.evDocMove = ev => {
if (this.resizing) {
ev.preventDefault();
ev.stopPropagation();
let w = ev.clientX - startPos.x;
let h = ev.clientY - startPos.y;
rectTarget.style.width = (startPos.w + w) + 'px';
rectTarget.style.height = (startPos.h + h) + 'px';
}
if (this.moving && rectTarget) {
ev.preventDefault();
ev.stopPropagation();
let x = ev.clientX - startPos.x;
let y = ev.clientY - startPos.y;
let top = elePos.y + y;
let offsetLeft = thumbRect.left - parentRect.left - THUMB_BORDER_WIDTH;
let offsetTop = thumbRect.top - parentRect.top - THUMB_BORDER_WIDTH;
top = Math.min(Math.max(top, offsetTop - THUMB_BORDER_WIDTH), offsetTop + thumbRect.height - eleRect.height);
left = Math.min(Math.max(left, offsetLeft - THUMB_BORDER_WIDTH), offsetLeft + thumbRect.width - eleRect.width);
rectTarget.style.top = top + 'px';
rectTarget.style.left = left + 'px';
}
});
}
rectZoomToPage(isMoving = false) {
let pdfViewer = this.pdfUI.pdfViewer;
let pdfDocRender = pdfViewer.getPDFDocRender();
let scrollWrap = pdfDocRender.viewerRender.scrollWrap;
let pageIndex = pdfDocRender.getCurrentPageIndex();
let pdfPageRender = pdfViewer.getPDFPageRender(pageIndex);
let prevScale = pdfPageRender.getScale();
let $eleRect = this.$thumbImageContainer.find('.fv__thumb-page .fv__thumb-view-rect.fv__rect_active');
let $eleThumb = $eleRect.parent().find('.fv__thumb-image');
let $thumbPage = $eleThumb.parents('.fv__thumb-page');
let thumbPos = $eleThumb.position();
let rectPos = $eleRect.position();
let viewportSize = {
width: scrollWrap.getWidth(),
height: scrollWrap.getHeight()
};
let thumbInfo = {
pos: {
x: $eleThumb.offset().left - $thumbPage.offset().left + THUMB_BORDER_WIDTH,
y: $eleThumb.offset().top - $thumbPage.offset().top + THUMB_BORDER_WIDTH
},
width: $eleThumb.outerWidth() - THUMB_BORDER_WIDTH,
height: $eleThumb.outerHeight() - THUMB_BORDER_WIDTH
}
};
let pdfPageSize = {
width: pdfPageRender.getShowWidth() / prevScale,
height: pdfPageRender.getShowHeight() / prevScale
};
let rectInfo = {
pos: {
x: rectPos.left - thumbInfo.pos.x + RECT_BORDER_WIDTH,
y: rectPos.top - thumbInfo.pos.y + RECT_BORDER_WIDTH
},
width: $eleRect.outerWidth() - RECT_BORDER_WIDTH * 2,
height: $eleRect.outerHeight() - RECT_BORDER_WIDTH * 2
}
};
let width = rectInfo.size.width;
let height = rectInfo.size.height;
if (width / viewportSize.width < height / viewportSize.height) {
width = height * viewportSize.width / viewportSize.height;
}
let pdfShowWidth = width / thumbInfo.size.width * pdfPageSize.width;
let scale = viewportSize.width / pdfShowWidth;
let x = rectInfo.pos.x / thumbInfo.size.width * pdfPageSize.width * prevScale;
let y = rectInfo.pos.y / thumbInfo.size.height * pdfPageSize.height * prevScale;
if (isMoving) {
pdfViewer.zoomTo(undefined, {
x,
y,
pageIndex,
type:'device'
});
} else {
pdfViewer.zoomTo(scale, {
x: this.prevPos.x / prevScale * scale,
y: this.prevPos.y / prevScale * scale,
pageIndex,
type:'device'
});
}
}
calcThumbnailRect(isPageChanged = false, newPageIndex = 0) {
let pageIndex = this.cachePageIndex || 0;
let $rects = this.$thumbImageContainer.find('.fv__thumb-view-rect');
if(!$rects.length)return;
if (isPageChanged || !$($rects[pageIndex]).hasClass('fv__rect_active')) {
$rects.hide().removeClass('fv__rect_active');
this.cachePageIndex = pageIndex = newPageIndex;
}
let $eleRect = $($rects[pageIndex]);
let $eleThumb = $eleRect.parent().find('.fv__thumb-image');
let $thumbPage = $eleThumb.parents('.fv__thumb-page');
let thumbPos = $eleThumb.position();
let pdfPageRender = this.pdfUI.pdfViewer.getPDFPageRender(pageIndex);
let thumbInfo = {
pos: {
x: $eleThumb.offset().left - $thumbPage.offset().left,
y: thumbPos.top
},
width: $eleThumb.width(),
height: $eleThumb.height()
}
};
let pageVisibleRect = pdfPageRender.getContainerVisibleRect();
let pdfPageInfo = {
visible: {
x: pageVisibleRect.left,
y: pageVisibleRect.top,
width: pageVisibleRect.right - pageVisibleRect.left,
height: pageVisibleRect.bottom - pageVisibleRect.top
},
width: pdfPageRender.getShowWidth(),
height: pdfPageRender.getShowHeight()
}
};
let x = thumbInfo.pos.x + pdfPageInfo.visible.x * (thumbInfo.size.width / pdfPageInfo.size.width);
let y = thumbInfo.pos.y + pdfPageInfo.visible.y * (thumbInfo.size.height / pdfPageInfo.size.height);
let width = pdfPageInfo.visible.width * (thumbInfo.size.width / pdfPageInfo.size.width);
let height = pdfPageInfo.visible.height * (thumbInfo.size.height / pdfPageInfo.size.height);
this.prevPos.x = pdfPageInfo.visible.x;
this.prevPos.y = pdfPageInfo.visible.y;
if (Number.isNaN(width) || width <= 0 || Number.isNaN(height) || height <= 0) return;
$eleRect.css('top', y - RECT_BORDER_WIDTH)
.css('left', x - RECT_BORDER_WIDTH)
.css('width', width + RECT_BORDER_WIDTH * 2)
.css('height', height + RECT_BORDER_WIDTH * 2)
.show()
.addClass('fv__rect_active');
isSafari && $eleRect.addClass('fv__thumb-view-safari');
}
updateVisiblePages(enforce) {
if(!$(this.element).is(':visible')) {
return;
}
adjustContainerFlexBox(this.$thumbImageContainer);
const $pages = this.$pages;
let visiblePages = [];
let visibleClientRect = this.$thumbImageContainer.parent()[0].getBoundingClientRect();
if (currentPageIndex >= pageCount) {
currentPageIndex = pageCount - 1;
}
let i = currentPageIndex, j = currentPageIndex + 1;
while (i >= 0) {
let clientRect = $pages[i].getBoundingClientRect();
if (clientRect.bottom < visibleClientRect.top) {
break;
}
if (isRectsOverlap(clientRect, visibleClientRect)) {
visiblePages.unshift(i);
}
i--;
}
while (j < $pages.length) {
let clientRect = $pages[j].getBoundingClientRect();
if (clientRect.top > visibleClientRect.bottom) {
break;
}
if (isRectsOverlap(clientRect, visibleClientRect)) {
visiblePages.push(j);
}
j++;
}
const currentScaleRatio = this.zoomService.getScaleRatio();
if (!enforce
&& this.visiblePages.length === visiblePages.length
&& !this.visiblePages.reduce((pre, pageIdx, idx) => pre ^ pageIdx ^ visiblePages[idx], 0)
&& this.lastScaleRatio === currentScaleRatio) {
return;
}
this.visiblePages = visiblePages;
this.lastScaleRatio = currentScaleRatio;
const promises = visiblePages.map(i => {
return this.controller.updatePageThumbImg(i);
});
return Promise.all(promises);
}
insertThumb(pageIndex, needGoto = true) {
let pageNum = pageIndex + 1;
let htmlTemplate = compileThumbTemplate(pageNum);
if (!this.zoomService.scaleEqualInitialize()) {
let $htmlTemplate = $(htmlTemplate);
const width = THUMBNAIL_PAGE_BASIS_WIDTH * this.zoomService.zoomToScaleRatio;
const height = THUMBNAIL_PAGE_BASIS_HEIGHT * this.zoomService.zoomToScaleRatio;
$htmlTemplate.css({
width: `${width}px`,
height: `${height}px`
})
htmlTemplate = $htmlTemplate;
}
if (this.$pages.length === 0) {
this.$thumbImageContainer.append(htmlTemplate);
}
if (pageIndex == this.$pages.length) {
$(this.$pages[pageIndex - 1]).
after(htmlTemplate);
} else
$(this.$pages[pageIndex]).
before(htmlTemplate);
this.$pages = this.$thumbImageContainer.find(".fv__thumb-page");
if (needGoto) {
this.updatePageLabel(pageIndex);
this.updateVisiblePages(true);
}
}
removeThumb(index) {
let $pages = this.$pages;
if (!$pages) return;
this.$pages = this.$thumbImageContainer.find(".fv__thumb-page");
this.updatePageLabel(index);
this.updateVisiblePages(true);
}
removeThumbs(pageIndexes){
pageIndexes.forEach(index=>{
let $pages = this.$pages;
if(!$pages)return;
})
this.$pages=this.$thumbImageContainer.find('.fv__thumb-page');
this.updateVisiblePages(true);
}
displayThumbImg(pageIndex, data) {
let $pageThumb = $(this.$pages[pageIndex]);
if($pageThumb.length < 1) {
return;
}
let eCanvas = $pageThumb.find(".fv__thumb-image")[0];
eCanvas.removeClass("fv__hide");
eCanvas.width = data.width;
eCanvas.height = data.height;
let $pageContainer = $pageThumb.find(".fv__thumb-page-container")
$pageContainer.addClass("loading");
const ratioCanvas = data.width / data.height;
const ratioContainer = $pageContainer.width() / $pageContainer.height();
if(ratioContainer !== 0) {
if(ratioCanvas < ratioContainer) {
const percentRatio = (ratioCanvas / ratioContainer) * 100;
eCanvas.style.maxWidth = percentRatio.toString() + "%";
eCanvas.style.maxHeight = "100%";
} else {
const percentRatio = (ratioContainer / ratioCanvas ) * 100;
eCanvas.style.maxHeight = percentRatio.toString() + "%";
eCanvas.style.maxWidth = "100%";
}
}
let ctx = eCanvas.getContext("2d");
if (data.buffer) {
let buffer = new (Uint8ClampedArray || Uint8Array)(data.buffer);
let img = ctx.createImageData(data.width, data.height);
img.data.set(buffer);
ctx.putImageData(img, 0, 0);
$pageContainer.removeClass("loading");
} else if (data.image) {
img.onload = function() {
ctx.drawImage(img, 0, 0);
URL.revokeObjectURL(img.src);
$pageContainer.removeClass("loading");
};
img.src = URL.createObjectURL(data.image);
}
if (pageIndex === this.cachePageIndex) this.calcThumbnailRect(true, pageIndex)
}
highlightMenuTarget(pageIndex) {
let $thumbPages = this.$pages;
if ($thumbPages[pageIndex]) {
this.$html
.find(".fv__active_contextmenu")
.removeClass("fv__active_contextmenu");
let $activeThumb = $($thumbPages[pageIndex]);
$activeThumb.addClass("fv__active_contextmenu");
}
}
highlightPage(pageIndex, enforce) {
this.
getPDFUI().pdfViewer.keyboard.defaultDeleteBinderName =
'thumbUIComponent';
const activeEle = this.$html.find(".fv__active");
const hasCurActiveIndex = activeEle.length === 1 && (activeEle.data('page-index') !== pageIndex);
const newPageIndex = typeof this.fromClickThumb === 'number' ? this.fromClickThumb : pageIndex;
if (this.fromClickThumb !== pageIndex || hasCurActiveIndex) {
let thumbPages = this.$html.find(".fv__thumb-page");
this.$html.find(".fv__active").removeClass("fv__active");
let $activeThumb = $(thumbPages[newPageIndex]);
$activeThumb.addClass("fv__active");
let $parent = this.$thumbImageContainerBox;
const thumbTop = $parent.offset().top + 10;
let offset = $activeThumb.offset();
let top = offset && offset.top;
if (top && top !== thumbTop) {
let currentTop = $parent.scrollTop();
$parent.scrollTop(currentTop + top - thumbTop);
}
}
this.calcThumbnailRect(true, newPageIndex);
this.doPageAction(this.previePageIndex, pageIndex);
this.fromClickThumb = null;
this.previePageIndex = pageIndex;
this.updateVisiblePages(enforce);
}
doPageAction(fromPageIndex, targetPageIndex) {
if(fromPageIndex === targetPageIndex || fromPageIndex === undefined) return;
const selectedThumb = $('.fv__thumb-page.fv__active');
if(selectedThumb.length > 1) return;
this.pdfUI.eventEmitter.emit(Events.thumbnailClicked, { fromPageIndex, targetPageIndex });
}
async updatePageLabel(from, to) {
this.$pages = this.$thumbImageContainer.find(".fv__thumb-page");
let $pageThumbs = this.$pages;
if (typeof to === 'undefined') {
to = $pageThumbs.length;
}
const logicalPageNumChecked = isPageLabelSetting();
let hasLabel = false;
let labels = [];
if (logicalPageNumChecked) {
const labelsObj = await this._checkAndGetLabels();
hasLabel = labelsObj.hasLabel;
labels = labelsObj.labels;
}
for (let i = from; i <= to; i++) {
const label = logicalPageNumChecked && hasLabel ? htmlCharacter2Entity(labels[i]) : i + 1;
let $pageThumb = $($pageThumbs[i]);
let $pageIndexDiv = $pageThumb.find(".fv__thumb-page-index");
$pageIndexDiv.html(label);
$pageThumb.attr("data-page-index", i);
$pageThumb.data("page-index", i);
}
}
reset() {
const $rects = this.$thumbImageContainer.find('.fv__thumb-view-rect');
resetContainerStyle(this.$thumbImageContainer);
this.fromClickThumb = null;
$(document).
off(
'mouseup', this.evDocUp);
$(document).
off(
'mousemove', this.evDocMove);
$rects.off('mousedown', this.evTnRectDown);
this.evDocUp = null;
this.evDocMove = null;
this.evTnRectDown = null;
}
copyPages(sourceIndexs, destIndex) {
const pages = [];
let tempArray = [];
sourceIndexs.forEach(item => {
if(tempArray.length > 0 && item !== tempArray[tempArray.length - 1] + 2) {
pages.push(tempArray);
tempArray = [];
}
if(tempArray.length > 1) {
tempArray[1] = item;
} else {
tempArray.push(item);
}
});
pages.push(tempArray);
this.controller.copyPages(pages, destIndex);
}
movePages(sourceIndexs, destIndex) {
sourceIndexs = sourceIndexs.map(sourceIndex => {
return [sourceIndex];
})
const pdfDoc = this.
getPDFUI().pdfViewer.currentPDFDoc;
pdfDoc.movePagesToThenUpdatePageLabel(sourceIndexs, destIndex);
}
movePageImage(src, dst) {
if (this.moveImageDone) {
this.moveImageDone = false;
return;
}
let min = Math.min(src, dst);
let max = Math.max(src, dst);
this.$pages = this.$thumbImageContainer.find(".fv__thumb-page");
for (let i = min; i <= max; i++) {
let $pageThumb = this.$pages.eq(i).find('.fv__thumb-page-container');;
$pageThumb.addClass("loading");
}
this.updatePageLabel(min, max);
this.updateVisiblePages(true);
}
movePagesImage (pageRange, destIndex, pageIdList) {
const min = Math.min(...pageRange, destIndex);
const max = Math.max(...pageRange, destIndex)
this.$pages = this.$thumbImageContainer.find('.fv__thumb-page');
for (let i = min; i <= max; i++) {
let $pageThumb = this.$pages.eq(i).find('.fv__thumb-page-container');
$pageThumb.addClass("loading");
}
this.updateVisiblePages(true);
}
checkAddonInstance (addonName) {
const addonMap = this.
getPDFUI().addonInstanceMap || {};
return addonMap[addonName];
}
getSelectedPages() {
const $activePages = this.$html.find(".fv__active");
let indexes = [];
$activePages.each((index, item) => {
indexes.push($(item).data("page-index"));
});
return indexes;
}
getAllActivePageIndex (exitIndexArray) {
let result = [];
let pageIndexs = exitIndexArray || [];
const $activePages = this.$html.find('.fv__active');
$activePages.each((index, target) => {
pageIndexs.push($(target).attr('data-page-index'));
});
pageIndexs = Array.from(new Set(pageIndexs)).sort((a, b) => a - b);
pageIndexs.reduce(function (a, b) {
if (!a || b - a > 1) {
result[result.length] = [+b + 1];
} else if (b - a === 1) {
result[result.length - 1].push(+b + 1);
}
return b;
}, '');
let ret = result.map(function (item) {
if (item.length === 1) return item[0];
return item[0] + '-' + item[item.length - 1];
});
return [result, ret];
}
get selectedPageRanges() {
const selectedPages = this.getSelectedPages();
const isSelected = selectedPages.length !== 0;
const currentPage =
.getCurrentPageIndex() + 1;
const pages = isSelected
: [currentPage];
return {
...__.business.range_.getPageRanges(pages, 1),
isSelected
};
}
checkContinuePage(ids) {
if(!Array.isArray(ids)) {
return false;
}
if(ids.length === 1) {
return true;
}
for (let i=0; i<ids.length; i++) {
if(i === ids.length - 1) {
return true;
}
if( ids[i] + 1 !== ids[i+1]) {
return false;
}
}
}
addDragEvent () {
const isCollaborationMode = this.pdfUI.customs && this.pdfUI.customs.isCollaborationMode();
if (isCollaborationMode || this.dragable) return ;
const e1 = this.$html.find(".fv__thumb-image-container")[0];
let dragLastNode = document.createElement("div");
dragLastNode.setAttribute("data-page-index","-1");
dragLastNode.style.borderStyle = "dashed";
this.dragable = Dragable.create(e1, {
draggable: "fv__thumb-page",
dragClass: "draggable-drag",
chosenClass: "thumb-sortable-ghost",
inventedNode: dragLastNode,
endStrict: false,
dragOverStrict: true,
checkIsMoveToRight: (target, info) => {
const targetRect = target.getBoundingClientRect();
const centerX = (targetRect.left + targetRect.right) * 0.5;
return info.mouseX > centerX;
},
onStart: (data) => {
const dom = $(data.dom);
if(!dom.hasClass("fv__active")) {
this.$html.find(".fv__active").removeClass("fv__active");
dom.addClass("fv__active");
}
},
onHover: (data) => {
},
onDrop: (data) => {
if (this.dragable.options.allowDrag) {
const dragFiles = data.dragFiles;
if (dragFiles.length === 0) {
return;
}
this.dragFileInsert(data);
} else {
this.dragable._removeClass(this.dragable.options.chosenClass, data.target);
}
},
onEnd: (data) => {
if(!data || !data.end) {
isTouchDevice && data?.fromAttrs?.pageIndex && (
this.
getPDFUI().goToPage(parseInt(data.fromAttrs.pageIndex, 10), 0, 0,
false)
);
return;
}
const $activePages = this.$html.find(".fv__active");
let ids = [];
$activePages.each((index, item) => {
ids.push($(item).data("page-index"));
});
if(ids.length < 1) {
return;
}
let toIndex = parseInt(data.endAttrs.pageIndex);
if (data.isMoveToRight) toIndex++;
const pageCnt = this.$pages.length;
if(toIndex === -1) {
toIndex = pageCnt;
}
if((isMacOS && data.end.altKey) || (!isMacOS && data.end.ctrlKey)) {
this.copyPages(ids, toIndex);
} else {
if(ids.length === 1) {
if(ids[0] === toIndex || ids[0] === toIndex - 1) {
return;
}
}else {
if(this.checkContinuePage(ids)) {
if(ids.includes(toIndex) || ids[ids.length - 1] === toIndex - 1) {
return;
}
}
}
this.movePages(ids, toIndex);
}
}
});
this.removeDragEvent();
});
}
removeDragEvent () {
this.dragable && this.dragable.destory();
this.dragable = null;
}
}
const isRectsOverlap = (src, dst) => {
let
left = Math.max(src.left, dst.left);
let top = Math.max(src.top, dst.top);
let bottom = Math.min(src.bottom, dst.bottom);
let
right = Math.min(src.right, dst.right);
return right >= left && bottom >= top;
};