Merge pull request #7254 from yurydelendik/eventbus

Introducing EventBus for the viewer UI.
This commit is contained in:
Jonas Jenwald 2016-04-28 15:19:49 +02:00
commit 61a4c740d2
19 changed files with 556 additions and 168 deletions

View File

@ -1,4 +1,4 @@
/* globals expect, it, describe, binarySearchFirstItem */ /* globals expect, it, describe, binarySearchFirstItem, EventBus */
'use strict'; 'use strict';
@ -30,5 +30,91 @@ describe('ui_utils', function() {
expect(binarySearchFirstItem([4, 5, 6], isGreater3)).toEqual(0); expect(binarySearchFirstItem([4, 5, 6], isGreater3)).toEqual(0);
}); });
}); });
describe('EventBus', function () {
it('dispatch event', function () {
var eventBus = new EventBus();
var count = 0;
eventBus.on('test', function () {
count++;
});
eventBus.dispatch('test');
expect(count).toEqual(1);
});
it('dispatch different event', function () {
var eventBus = new EventBus();
var count = 0;
eventBus.on('test', function () {
count++;
});
eventBus.dispatch('nottest');
expect(count).toEqual(0);
});
it('dispatch event multiple times', function () {
var eventBus = new EventBus();
var count = 0;
eventBus.dispatch('test');
eventBus.on('test', function () {
count++;
});
eventBus.dispatch('test');
eventBus.dispatch('test');
expect(count).toEqual(2);
});
it('dispatch event to multiple handlers', function () {
var eventBus = new EventBus();
var count = 0;
eventBus.on('test', function () {
count++;
});
eventBus.on('test', function () {
count++;
});
eventBus.dispatch('test');
expect(count).toEqual(2);
});
it('dispatch to detached', function () {
var eventBus = new EventBus();
var count = 0;
var listener = function () {
count++;
};
eventBus.on('test', listener);
eventBus.dispatch('test');
eventBus.off('test', listener);
eventBus.dispatch('test');
expect(count).toEqual(1);
});
it('dispatch to wrong detached', function () {
var eventBus = new EventBus();
var count = 0;
eventBus.on('test', function () {
count++;
});
eventBus.dispatch('test');
eventBus.off('test', function () {
count++;
});
eventBus.dispatch('test');
expect(count).toEqual(2);
});
it('dispatch to detached during handling', function () {
var eventBus = new EventBus();
var count = 0;
var listener1 = function () {
eventBus.off('test', listener2);
count++;
};
var listener2 = function () {
eventBus.off('test', listener1);
count++;
};
eventBus.on('test', listener1);
eventBus.on('test', listener2);
eventBus.dispatch('test');
eventBus.dispatch('test');
expect(count).toEqual(2);
});
});
}); });

View File

@ -28,7 +28,7 @@
'pdfjs-web/pdf_rendering_queue', 'pdfjs-web/pdf_link_service', 'pdfjs-web/pdf_rendering_queue', 'pdfjs-web/pdf_link_service',
'pdfjs-web/pdf_outline_viewer', 'pdfjs-web/overlay_manager', 'pdfjs-web/pdf_outline_viewer', 'pdfjs-web/overlay_manager',
'pdfjs-web/pdf_attachment_viewer', 'pdfjs-web/pdf_find_controller', 'pdfjs-web/pdf_attachment_viewer', 'pdfjs-web/pdf_find_controller',
'pdfjs-web/pdf_find_bar', 'pdfjs-web/pdfjs'], 'pdfjs-web/pdf_find_bar', 'pdfjs-web/dom_events', 'pdfjs-web/pdfjs'],
factory); factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'), require('./download_manager.js'), factory(exports, require('./ui_utils.js'), require('./download_manager.js'),
@ -41,7 +41,7 @@
require('./pdf_link_service.js'), require('./pdf_outline_viewer.js'), require('./pdf_link_service.js'), require('./pdf_outline_viewer.js'),
require('./overlay_manager.js'), require('./pdf_attachment_viewer.js'), require('./overlay_manager.js'), require('./pdf_attachment_viewer.js'),
require('./pdf_find_controller.js'), require('./pdf_find_bar.js'), require('./pdf_find_controller.js'), require('./pdf_find_bar.js'),
require('./pdfjs.js')); require('./dom_events.js'), require('./pdfjs.js'));
} else { } else {
factory((root.pdfjsWebApp = {}), root.pdfjsWebUIUtils, factory((root.pdfjsWebApp = {}), root.pdfjsWebUIUtils,
root.pdfjsWebDownloadManager, root.pdfjsWebPDFHistory, root.pdfjsWebDownloadManager, root.pdfjsWebPDFHistory,
@ -53,7 +53,7 @@
root.pdfjsWebPDFRenderingQueue, root.pdfjsWebPDFLinkService, root.pdfjsWebPDFRenderingQueue, root.pdfjsWebPDFLinkService,
root.pdfjsWebPDFOutlineViewer, root.pdfjsWebOverlayManager, root.pdfjsWebPDFOutlineViewer, root.pdfjsWebOverlayManager,
root.pdfjsWebPDFAttachmentViewer, root.pdfjsWebPDFFindController, root.pdfjsWebPDFAttachmentViewer, root.pdfjsWebPDFFindController,
root.pdfjsWebPDFFindBar, root.pdfjsWebPDFJS); root.pdfjsWebPDFFindBar, root.pdfjsWebDOMEvents, root.pdfjsWebPDFJS);
} }
}(this, function (exports, uiUtilsLib, downloadManagerLib, pdfHistoryLib, }(this, function (exports, uiUtilsLib, downloadManagerLib, pdfHistoryLib,
preferencesLib, pdfSidebarLib, viewHistoryLib, preferencesLib, pdfSidebarLib, viewHistoryLib,
@ -62,7 +62,7 @@
pdfViewerLib, pdfRenderingQueueLib, pdfLinkServiceLib, pdfViewerLib, pdfRenderingQueueLib, pdfLinkServiceLib,
pdfOutlineViewerLib, overlayManagerLib, pdfOutlineViewerLib, overlayManagerLib,
pdfAttachmentViewerLib, pdfFindControllerLib, pdfFindBarLib, pdfAttachmentViewerLib, pdfFindControllerLib, pdfFindBarLib,
pdfjsLib) { domEventsLib, pdfjsLib) {
var UNKNOWN_SCALE = uiUtilsLib.UNKNOWN_SCALE; var UNKNOWN_SCALE = uiUtilsLib.UNKNOWN_SCALE;
var DEFAULT_SCALE_VALUE = uiUtilsLib.DEFAULT_SCALE_VALUE; var DEFAULT_SCALE_VALUE = uiUtilsLib.DEFAULT_SCALE_VALUE;
@ -92,6 +92,7 @@ var OverlayManager = overlayManagerLib.OverlayManager;
var PDFAttachmentViewer = pdfAttachmentViewerLib.PDFAttachmentViewer; var PDFAttachmentViewer = pdfAttachmentViewerLib.PDFAttachmentViewer;
var PDFFindController = pdfFindControllerLib.PDFFindController; var PDFFindController = pdfFindControllerLib.PDFFindController;
var PDFFindBar = pdfFindBarLib.PDFFindBar; var PDFFindBar = pdfFindBarLib.PDFFindBar;
var getGlobalEventBus = domEventsLib.getGlobalEventBus;
var DEFAULT_SCALE_DELTA = 1.1; var DEFAULT_SCALE_DELTA = 1.1;
var MIN_SCALE = 0.25; var MIN_SCALE = 0.25;
@ -166,6 +167,8 @@ var PDFViewerApplication = {
store: null, store: null,
/** @type {DownloadManager} */ /** @type {DownloadManager} */
downloadManager: null, downloadManager: null,
/** @type {EventBus} */
eventBus: null,
pageRotation: 0, pageRotation: 0,
isInitialViewSet: false, isInitialViewSet: false,
animationStartedPromise: null, animationStartedPromise: null,
@ -182,11 +185,17 @@ var PDFViewerApplication = {
configure(pdfjsLib.PDFJS); configure(pdfjsLib.PDFJS);
this.appConfig = appConfig; this.appConfig = appConfig;
var eventBus = appConfig.eventBus || getGlobalEventBus();
this.eventBus = eventBus;
this.bindEvents();
var pdfRenderingQueue = new PDFRenderingQueue(); var pdfRenderingQueue = new PDFRenderingQueue();
pdfRenderingQueue.onIdle = this.cleanup.bind(this); pdfRenderingQueue.onIdle = this.cleanup.bind(this);
this.pdfRenderingQueue = pdfRenderingQueue; this.pdfRenderingQueue = pdfRenderingQueue;
var pdfLinkService = new PDFLinkService(); var pdfLinkService = new PDFLinkService({
eventBus: eventBus
});
this.pdfLinkService = pdfLinkService; this.pdfLinkService = pdfLinkService;
var downloadManager = this.externalServices.createDownloadManager(); var downloadManager = this.externalServices.createDownloadManager();
@ -197,6 +206,7 @@ var PDFViewerApplication = {
this.pdfViewer = new PDFViewer({ this.pdfViewer = new PDFViewer({
container: container, container: container,
viewer: viewer, viewer: viewer,
eventBus: eventBus,
renderingQueue: pdfRenderingQueue, renderingQueue: pdfRenderingQueue,
linkService: pdfLinkService, linkService: pdfLinkService,
downloadManager: downloadManager downloadManager: downloadManager
@ -216,7 +226,8 @@ var PDFViewerApplication = {
this.preferences = Preferences; this.preferences = Preferences;
this.pdfHistory = new PDFHistory({ this.pdfHistory = new PDFHistory({
linkService: pdfLinkService linkService: pdfLinkService,
eventBus: this.eventBus
}); });
pdfLinkService.setHistory(this.pdfHistory); pdfLinkService.setHistory(this.pdfHistory);
@ -237,19 +248,20 @@ var PDFViewerApplication = {
this.findBar.updateUIState(state, previous, matchCount); this.findBar.updateUIState(state, previous, matchCount);
} }
}.bind(this); }.bind(this);
this.findController.listenWindowEvents();
this.pdfViewer.setFindController(this.findController); this.pdfViewer.setFindController(this.findController);
// FIXME better PDFFindBar constructor parameters // FIXME better PDFFindBar constructor parameters
var findBarConfig = Object.create(appConfig.findBar); var findBarConfig = Object.create(appConfig.findBar);
findBarConfig.findController = this.findController; findBarConfig.findController = this.findController;
findBarConfig.eventBus = this.eventBus;
this.findBar = new PDFFindBar(findBarConfig); this.findBar = new PDFFindBar(findBarConfig);
this.overlayManager = OverlayManager; this.overlayManager = OverlayManager;
this.handTool = new HandTool({ this.handTool = new HandTool({
container: container, container: container,
eventBus: this.eventBus,
toggleHandTool: appConfig.secondaryToolbar.toggleHandTool toggleHandTool: appConfig.secondaryToolbar.toggleHandTool
}); });
@ -265,6 +277,7 @@ var PDFViewerApplication = {
container: container, container: container,
viewer: viewer, viewer: viewer,
pdfViewer: this.pdfViewer, pdfViewer: this.pdfViewer,
eventBus: this.eventBus,
contextMenuItems: [ contextMenuItems: [
{ element: appConfig.fullscreen.contextFirstPage, { element: appConfig.fullscreen.contextFirstPage,
handler: toolbar.firstPageClick.bind(toolbar) }, handler: toolbar.firstPageClick.bind(toolbar) },
@ -282,11 +295,13 @@ var PDFViewerApplication = {
this.pdfOutlineViewer = new PDFOutlineViewer({ this.pdfOutlineViewer = new PDFOutlineViewer({
container: appConfig.sidebar.outlineView, container: appConfig.sidebar.outlineView,
eventBus: this.eventBus,
linkService: pdfLinkService, linkService: pdfLinkService,
}); });
this.pdfAttachmentViewer = new PDFAttachmentViewer({ this.pdfAttachmentViewer = new PDFAttachmentViewer({
container: appConfig.sidebar.attachmentsView, container: appConfig.sidebar.attachmentsView,
eventBus: this.eventBus,
downloadManager: downloadManager downloadManager: downloadManager
}); });
@ -295,6 +310,7 @@ var PDFViewerApplication = {
sidebarConfig.pdfViewer = this.pdfViewer; sidebarConfig.pdfViewer = this.pdfViewer;
sidebarConfig.pdfThumbnailViewer = this.pdfThumbnailViewer; sidebarConfig.pdfThumbnailViewer = this.pdfThumbnailViewer;
sidebarConfig.pdfOutlineViewer = this.pdfOutlineViewer; sidebarConfig.pdfOutlineViewer = this.pdfOutlineViewer;
sidebarConfig.eventBus = this.eventBus;
this.pdfSidebar = new PDFSidebar(sidebarConfig); this.pdfSidebar = new PDFSidebar(sidebarConfig);
this.pdfSidebar.onToggled = this.forceRendering.bind(this); this.pdfSidebar.onToggled = this.forceRendering.bind(this);
@ -856,9 +872,7 @@ var PDFViewerApplication = {
firstPagePromise.then(function(pdfPage) { firstPagePromise.then(function(pdfPage) {
downloadedPromise.then(function () { downloadedPromise.then(function () {
var event = document.createEvent('CustomEvent'); self.eventBus.dispatch('documentload', {source: self});
event.initCustomEvent('documentload', true, true, {});
window.dispatchEvent(event);
}); });
self.loadingBar.setWidth(self.appConfig.viewerContainer); self.loadingBar.setWidth(self.appConfig.viewerContainer);
@ -1215,6 +1229,29 @@ var PDFViewerApplication = {
return; return;
} }
this.pdfPresentationMode.mouseScroll(delta); this.pdfPresentationMode.mouseScroll(delta);
},
bindEvents: function pdfViewBindEvents() {
var eventBus = this.eventBus;
eventBus.on('resize', webViewerResize);
eventBus.on('localized', webViewerLocalized);
eventBus.on('hashchange', webViewerHashchange);
eventBus.on('beforeprint', this.beforePrint.bind(this));
eventBus.on('afterprint', this.afterPrint.bind(this));
eventBus.on('pagerendered', webViewerPageRendered);
eventBus.on('textlayerrendered', webViewerTextLayerRendered);
eventBus.on('updateviewarea', webViewerUpdateViewarea);
eventBus.on('pagechange', webViewerPageChange);
eventBus.on('scalechange', webViewerScaleChange);
eventBus.on('sidebarviewchanged', webViewerSidebarViewChanged);
eventBus.on('pagemode', webViewerPageMode);
eventBus.on('namedaction', webViewerNamedAction);
eventBus.on('presentationmodechanged', webViewerPresentationModeChanged);
eventBus.on('find', webViewerFind);
//#if GENERIC
eventBus.on('fileinputchange', webViewerFileInputChange);
//#endif
} }
}; };
@ -1390,9 +1427,7 @@ function webViewerInitialized() {
appConfig.sidebar.mainContainer.addEventListener('transitionend', appConfig.sidebar.mainContainer.addEventListener('transitionend',
function(e) { function(e) {
if (e.target === /* mainContainer */ this) { if (e.target === /* mainContainer */ this) {
var event = document.createEvent('UIEvents'); PDFViewerApplication.eventBus.dispatch('resize');
event.initUIEvent('resize', false, false, window, 0);
window.dispatchEvent(event);
} }
}, true); }, true);
@ -1486,8 +1521,8 @@ function webViewerInitialized() {
//#endif //#endif
} }
document.addEventListener('pagerendered', function (e) { function webViewerPageRendered(e) {
var pageNumber = e.detail.pageNumber; var pageNumber = e.pageNumber;
var pageIndex = pageNumber - 1; var pageIndex = pageNumber - 1;
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex); var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
@ -1531,10 +1566,10 @@ document.addEventListener('pagerendered', function (e) {
}); });
}); });
//#endif //#endif
}, true); }
document.addEventListener('textlayerrendered', function (e) { function webViewerTextLayerRendered(e) {
var pageIndex = e.detail.pageNumber - 1; var pageIndex = e.pageNumber - 1;
var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex); var pageView = PDFViewerApplication.pdfViewer.getPageView(pageIndex);
//#if !PRODUCTION //#if !PRODUCTION
@ -1553,14 +1588,14 @@ document.addEventListener('textlayerrendered', function (e) {
PDFViewerApplication.fallback(); PDFViewerApplication.fallback();
} }
//#endif //#endif
}, true); }
document.addEventListener('pagemode', function (evt) { function webViewerPageMode(e) {
if (!PDFViewerApplication.initialized) { if (!PDFViewerApplication.initialized) {
return; return;
} }
// Handle the 'pagemode' hash parameter, see also `PDFLinkService_setHash`. // Handle the 'pagemode' hash parameter, see also `PDFLinkService_setHash`.
var mode = evt.detail.mode, view; var mode = e.mode, view;
switch (mode) { switch (mode) {
case 'thumbs': case 'thumbs':
view = SidebarView.THUMBS; view = SidebarView.THUMBS;
@ -1580,15 +1615,15 @@ document.addEventListener('pagemode', function (evt) {
return; return;
} }
PDFViewerApplication.pdfSidebar.switchView(view, /* forceOpen = */ true); PDFViewerApplication.pdfSidebar.switchView(view, /* forceOpen = */ true);
}, true); }
document.addEventListener('namedaction', function (e) { function webViewerNamedAction(e) {
if (!PDFViewerApplication.initialized) { if (!PDFViewerApplication.initialized) {
return; return;
} }
// Processing couple of named actions that might be useful. // Processing couple of named actions that might be useful.
// See also PDFLinkService.executeNamedAction // See also PDFLinkService.executeNamedAction
var action = e.detail.action; var action = e.action;
switch (action) { switch (action) {
case 'GoToPage': case 'GoToPage':
PDFViewerApplication.appConfig.toolbar.pageNumber.focus(); PDFViewerApplication.appConfig.toolbar.pageNumber.focus();
@ -1600,17 +1635,17 @@ document.addEventListener('namedaction', function (e) {
} }
break; break;
} }
}, true); }
window.addEventListener('presentationmodechanged', function (e) { function webViewerPresentationModeChanged(e) {
var active = e.detail.active; var active = e.active;
var switchInProgress = e.detail.switchInProgress; var switchInProgress = e.switchInProgress;
PDFViewerApplication.pdfViewer.presentationModeState = PDFViewerApplication.pdfViewer.presentationModeState =
switchInProgress ? PresentationModeState.CHANGING : switchInProgress ? PresentationModeState.CHANGING :
active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL; active ? PresentationModeState.FULLSCREEN : PresentationModeState.NORMAL;
}); }
window.addEventListener('sidebarviewchanged', function (evt) { function webViewerSidebarViewChanged(e) {
if (!PDFViewerApplication.initialized) { if (!PDFViewerApplication.initialized) {
return; return;
} }
@ -1623,15 +1658,15 @@ window.addEventListener('sidebarviewchanged', function (evt) {
return; return;
} }
store.initializedPromise.then(function() { store.initializedPromise.then(function() {
store.set('sidebarView', evt.detail.view).catch(function() {}); store.set('sidebarView', e.view).catch(function() {});
}); });
}, true); }
window.addEventListener('updateviewarea', function (evt) { function webViewerUpdateViewarea(e) {
if (!PDFViewerApplication.initialized) { if (!PDFViewerApplication.initialized) {
return; return;
} }
var location = evt.location, store = PDFViewerApplication.store; var location = e.location, store = PDFViewerApplication.store;
if (store) { if (store) {
store.initializedPromise.then(function() { store.initializedPromise.then(function() {
@ -1663,9 +1698,13 @@ window.addEventListener('updateviewarea', function (evt) {
} else { } else {
pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR); pageNumberInput.classList.add(PAGE_NUMBER_LOADING_INDICATOR);
} }
}, true); }
window.addEventListener('resize', function webViewerResize(evt) { window.addEventListener('resize', function webViewerResize(evt) {
PDFViewerApplication.eventBus.dispatch('resize');
});
function webViewerResize() {
if (PDFViewerApplication.initialized) { if (PDFViewerApplication.initialized) {
var currentScaleValue = PDFViewerApplication.pdfViewer.currentScaleValue; var currentScaleValue = PDFViewerApplication.pdfViewer.currentScaleValue;
if (currentScaleValue === 'auto' || if (currentScaleValue === 'auto' ||
@ -1684,11 +1723,16 @@ window.addEventListener('resize', function webViewerResize(evt) {
// Set the 'max-height' CSS property of the secondary toolbar. // Set the 'max-height' CSS property of the secondary toolbar.
SecondaryToolbar.setMaxHeight(PDFViewerApplication.appConfig.mainContainer); SecondaryToolbar.setMaxHeight(PDFViewerApplication.appConfig.mainContainer);
}); }
window.addEventListener('hashchange', function webViewerHashchange(evt) { window.addEventListener('hashchange', function webViewerHashchange(evt) {
if (PDFViewerApplication.pdfHistory.isHashChangeUnlocked) {
var hash = document.location.hash.substring(1); var hash = document.location.hash.substring(1);
PDFViewerApplication.eventBus.dispatch('hashchange', {hash: hash});
});
function webViewerHashchange(e) {
if (PDFViewerApplication.pdfHistory.isHashChangeUnlocked) {
var hash = e.hash;
if (!hash) { if (!hash) {
return; return;
} }
@ -1698,7 +1742,7 @@ window.addEventListener('hashchange', function webViewerHashchange(evt) {
PDFViewerApplication.pdfLinkService.setHash(hash); PDFViewerApplication.pdfLinkService.setHash(hash);
} }
} }
}); }
//#if GENERIC //#if GENERIC
window.addEventListener('change', function webViewerChange(evt) { window.addEventListener('change', function webViewerChange(evt) {
@ -1706,7 +1750,12 @@ window.addEventListener('change', function webViewerChange(evt) {
if (!files || files.length === 0) { if (!files || files.length === 0) {
return; return;
} }
var file = files[0]; PDFViewerApplication.eventBus.dispatch('fileinputchange',
{fileInput: evt.target});
}, true);
function webViewerFileInputChange(e) {
var file = e.fileInput.files[0];
if (!pdfjsLib.PDFJS.disableCreateObjectURL && if (!pdfjsLib.PDFJS.disableCreateObjectURL &&
typeof URL !== 'undefined' && URL.createObjectURL) { typeof URL !== 'undefined' && URL.createObjectURL) {
@ -1730,7 +1779,7 @@ window.addEventListener('change', function webViewerChange(evt) {
appConfig.secondaryToolbar.viewBookmark.setAttribute('hidden', 'true'); appConfig.secondaryToolbar.viewBookmark.setAttribute('hidden', 'true');
appConfig.toolbar.download.setAttribute('hidden', 'true'); appConfig.toolbar.download.setAttribute('hidden', 'true');
appConfig.secondaryToolbar.download.setAttribute('hidden', 'true'); appConfig.secondaryToolbar.download.setAttribute('hidden', 'true');
}, true); }
//#endif //#endif
function selectScaleOption(value) { function selectScaleOption(value) {
@ -1749,6 +1798,10 @@ function selectScaleOption(value) {
} }
window.addEventListener('localized', function localized(evt) { window.addEventListener('localized', function localized(evt) {
PDFViewerApplication.eventBus.dispatch('localized');
});
function webViewerLocalized() {
document.getElementsByTagName('html')[0].dir = mozL10n.getDirection(); document.getElementsByTagName('html')[0].dir = mozL10n.getDirection();
PDFViewerApplication.animationStartedPromise.then(function() { PDFViewerApplication.animationStartedPromise.then(function() {
@ -1772,19 +1825,28 @@ window.addEventListener('localized', function localized(evt) {
// Set the 'max-height' CSS property of the secondary toolbar. // Set the 'max-height' CSS property of the secondary toolbar.
SecondaryToolbar.setMaxHeight(PDFViewerApplication.appConfig.mainContainer); SecondaryToolbar.setMaxHeight(PDFViewerApplication.appConfig.mainContainer);
}); });
}, true); }
window.addEventListener('scalechange', function scalechange(evt) { function webViewerFind(e) {
PDFViewerApplication.findController.executeCommand('find' + e.type, {
query: e.query,
caseSensitive: e.caseSensitive,
highlightAll: e.highlightAll,
findPrevious: e.findPrevious
});
}
function webViewerScaleChange(e) {
var appConfig = PDFViewerApplication.appConfig; var appConfig = PDFViewerApplication.appConfig;
appConfig.toolbar.zoomOut.disabled = (evt.scale === MIN_SCALE); appConfig.toolbar.zoomOut.disabled = (e.scale === MIN_SCALE);
appConfig.toolbar.zoomIn.disabled = (evt.scale === MAX_SCALE); appConfig.toolbar.zoomIn.disabled = (e.scale === MAX_SCALE);
// Update the 'scaleSelect' DOM element. // Update the 'scaleSelect' DOM element.
var predefinedValueFound = selectScaleOption(evt.presetValue || var predefinedValueFound = selectScaleOption(e.presetValue ||
'' + evt.scale); '' + e.scale);
if (!predefinedValueFound) { if (!predefinedValueFound) {
var customScaleOption = appConfig.toolbar.customScaleOption; var customScaleOption = appConfig.toolbar.customScaleOption;
var customScale = Math.round(evt.scale * 10000) / 100; var customScale = Math.round(e.scale * 10000) / 100;
customScaleOption.textContent = customScaleOption.textContent =
mozL10n.get('page_scale_percent', { scale: customScale }, '{{scale}}%'); mozL10n.get('page_scale_percent', { scale: customScale }, '{{scale}}%');
customScaleOption.selected = true; customScaleOption.selected = true;
@ -1793,11 +1855,11 @@ window.addEventListener('scalechange', function scalechange(evt) {
return; return;
} }
PDFViewerApplication.pdfViewer.update(); PDFViewerApplication.pdfViewer.update();
}, true); }
window.addEventListener('pagechange', function pagechange(evt) { function webViewerPageChange(e) {
var page = evt.pageNumber; var page = e.pageNumber;
if (evt.previousPageNumber !== page) { if (e.previousPageNumber !== page) {
PDFViewerApplication.appConfig.toolbar.pageNumber.value = page; PDFViewerApplication.appConfig.toolbar.pageNumber.value = page;
if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) { if (PDFViewerApplication.pdfSidebar.isThumbnailViewVisible) {
@ -1819,7 +1881,7 @@ window.addEventListener('pagechange', function pagechange(evt) {
Stats.add(page, pageView.stats); Stats.add(page, pageView.stats);
} }
} }
}, true); }
var zoomDisabled = false, zoomDisabledTimeout; var zoomDisabled = false, zoomDisabledTimeout;
function handleMouseWheel(evt) { function handleMouseWheel(evt) {
@ -1908,8 +1970,15 @@ window.addEventListener('keydown', function keydown(evt) {
break; break;
case 71: // g case 71: // g
if (!PDFViewerApplication.supportsIntegratedFind) { if (!PDFViewerApplication.supportsIntegratedFind) {
PDFViewerApplication.findBar.dispatchEvent('again', var findState = PDFViewerApplication.findController.state;
cmd === 5 || cmd === 12); if (findState) {
PDFViewerApplication.findController.executeCommand('findagain', {
query: findState.query,
caseSensitive: findState.caseSensitive,
highlightAll: findState.highlightAll,
findPrevious: cmd === 5 || cmd === 12
});
}
handled = true; handled = true;
} }
break; break;
@ -2127,11 +2196,11 @@ window.addEventListener('keydown', function keydown(evt) {
}); });
window.addEventListener('beforeprint', function beforePrint(evt) { window.addEventListener('beforeprint', function beforePrint(evt) {
PDFViewerApplication.beforePrint(); PDFViewerApplication.eventBus.dispatch('beforeprint');
}); });
window.addEventListener('afterprint', function afterPrint(evt) { window.addEventListener('afterprint', function afterPrint(evt) {
PDFViewerApplication.afterPrint(); PDFViewerApplication.eventBus.dispatch('afterprint');
}); });
(function animationStartedClosure() { (function animationStartedClosure() {

155
web/dom_events.js Normal file
View File

@ -0,0 +1,155 @@
/* Copyright 2016 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define('pdfjs-web/dom_events', ['exports', 'pdfjs-web/ui_utils'], factory);
} else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'));
} else {
factory((root.pdfjsWebDOMEvents = {}), root.pdfjsWebUIUtils);
}
}(this, function (exports, uiUtils) {
var EventBus = uiUtils.EventBus;
// Attaching to the application event bus to dispatch events to the DOM for
// backwards viewer API compatibility.
function attachDOMEventsToEventBus(eventBus) {
eventBus.on('documentload', function () {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('documentload', true, true, {});
window.dispatchEvent(event);
});
eventBus.on('pagerendered', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagerendered', true, true, {
pageNumber: e.pageNumber,
cssTransform: e.cssTransform,
});
e.source.div.dispatchEvent(event);
});
eventBus.on('textlayerrendered', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('textlayerrendered', true, true, {
pageNumber: e.pageNumber
});
e.source.textLayerDiv.dispatchEvent(event);
});
eventBus.on('pagechange', function (e) {
var event = document.createEvent('UIEvents');
event.initUIEvent('pagechange', true, true, window, 0);
event.updateInProgress = e.updateInProgress;
event.pageNumber = e.pageNumber;
event.previousPageNumber = e.previousPageNumber;
e.source.container.dispatchEvent(event);
});
eventBus.on('pagesinit', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagesinit', true, true, null);
e.source.container.dispatchEvent(event);
});
eventBus.on('pagesloaded', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagesloaded', true, true, {
pagesCount: e.pagesCount
});
e.source.container.dispatchEvent(event);
});
eventBus.on('scalechange', function (e) {
var event = document.createEvent('UIEvents');
event.initUIEvent('scalechange', true, true, window, 0);
event.scale = e.scale;
event.presetValue = e.presetValue;
e.source.container.dispatchEvent(event);
});
eventBus.on('updateviewarea', function (e) {
var event = document.createEvent('UIEvents');
event.initUIEvent('updateviewarea', true, true, window, 0);
event.location = e.location;
e.source.container.dispatchEvent(event);
});
eventBus.on('find', function (e) {
if (e.source === window) {
return; // event comes from FirefoxCom, no need to replicate
}
var event = document.createEvent('CustomEvent');
event.initCustomEvent('find' + e.type, true, true, {
query: e.query,
caseSensitive: e.caseSensitive,
highlightAll: e.highlightAll,
findPrevious: e.findPrevious
});
window.dispatchEvent(event);
});
eventBus.on('attachmentsloaded', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('attachmentsloaded', true, true, {
attachmentsCount: e.attachmentsCount
});
e.source.container.dispatchEvent(event);
});
eventBus.on('sidebarviewchanged', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('sidebarviewchanged', true, true, {
view: e.view,
});
e.source.outerContainer.dispatchEvent(event);
});
eventBus.on('pagemode', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('pagemode', true, true, {
mode: e.mode,
});
e.source.pdfViewer.container.dispatchEvent(event);
});
eventBus.on('namedaction', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('namedaction', true, true, {
action: e.action
});
e.source.pdfViewer.container.dispatchEvent(event);
});
eventBus.on('presentationmodechanged', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('presentationmodechanged', true, true, {
active: e.active,
switchInProgress: e.switchInProgress
});
window.dispatchEvent(event);
});
eventBus.on('outlineloaded', function (e) {
var event = document.createEvent('CustomEvent');
event.initCustomEvent('outlineloaded', true, true, {
outlineCount: e.outlineCount
});
e.source.container.dispatchEvent(event);
});
}
var globalEventBus = null;
function getGlobalEventBus() {
if (globalEventBus) {
return globalEventBus;
}
globalEventBus = new EventBus();
attachDOMEventsToEventBus(globalEventBus);
return globalEventBus;
}
exports.attachDOMEventsToEventBus = attachDOMEventsToEventBus;
exports.getGlobalEventBus = getGlobalEventBus;
}));

View File

@ -148,6 +148,32 @@ Preferences._readFromStorage = function (prefObj) {
}); });
}; };
(function listenFindEvents() {
var events = [
'find',
'findagain',
'findhighlightallchange',
'findcasesensitivitychange'
];
var handleEvent = function (evt) {
if (!PDFViewerApplication.initialized) {
return;
}
PDFViewerApplication.eventBus.dispatch('find', {
source: window,
type: evt.type.substring('find'.length),
query: evt.detail.query,
caseSensitive: !!evt.detail.caseSensitive,
highlightAll: !!evt.detail.highlightAll,
findPrevious: !!evt.detail.findPrevious
});
}.bind(this);
for (var i = 0, len = events.length; i < len; i++) {
window.addEventListener(events[i], handleEvent);
}
})();
function FirefoxComDataRangeTransport(length, initialData) { function FirefoxComDataRangeTransport(length, initialData) {
pdfjsLib.PDFDataRangeTransport.call(this, length, initialData); pdfjsLib.PDFDataRangeTransport.call(this, length, initialData);
} }

View File

@ -40,6 +40,7 @@ var SecondaryToolbar = secondaryToolbar.SecondaryToolbar;
* @property {HTMLDivElement} container - The document container. * @property {HTMLDivElement} container - The document container.
* @property {HTMLButtonElement} toggleHandTool - The button element for * @property {HTMLButtonElement} toggleHandTool - The button element for
* toggling the hand tool. * toggling the hand tool.
* @property {EventBus} eventBus - The application event bus.
*/ */
/** /**
@ -52,6 +53,7 @@ var HandTool = (function HandToolClosure() {
*/ */
function HandTool(options) { function HandTool(options) {
this.container = options.container; this.container = options.container;
this.eventBus = options.eventBus;
this.toggleHandTool = options.toggleHandTool; this.toggleHandTool = options.toggleHandTool;
this.wasActive = false; this.wasActive = false;
@ -79,7 +81,7 @@ var HandTool = (function HandToolClosure() {
if (this.toggleHandTool) { if (this.toggleHandTool) {
this.toggleHandTool.addEventListener('click', this.toggle.bind(this)); this.toggleHandTool.addEventListener('click', this.toggle.bind(this));
window.addEventListener('localized', function (evt) { this.eventBus.on('localized', function (e) {
Preferences.get('enableHandToolOnLoad').then(function resolved(value) { Preferences.get('enableHandToolOnLoad').then(function resolved(value) {
if (value) { if (value) {
this.handTool.activate(); this.handTool.activate();
@ -87,11 +89,11 @@ var HandTool = (function HandToolClosure() {
}.bind(this), function rejected(reason) {}); }.bind(this), function rejected(reason) {});
}.bind(this)); }.bind(this));
window.addEventListener('presentationmodechanged', function (evt) { this.eventBus.on('presentationmodechanged', function (e) {
if (evt.detail.switchInProgress) { if (e.switchInProgress) {
return; return;
} }
if (evt.detail.active) { if (e.active) {
this.enterPresentationMode(); this.enterPresentationMode();
} else { } else {
this.exitPresentationMode(); this.exitPresentationMode();

View File

@ -29,6 +29,7 @@
/** /**
* @typedef {Object} PDFAttachmentViewerOptions * @typedef {Object} PDFAttachmentViewerOptions
* @property {HTMLDivElement} container - The viewer element. * @property {HTMLDivElement} container - The viewer element.
* @property {EventBus} eventBus - The application event bus.
* @property {DownloadManager} downloadManager - The download manager. * @property {DownloadManager} downloadManager - The download manager.
*/ */
@ -48,6 +49,7 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
function PDFAttachmentViewer(options) { function PDFAttachmentViewer(options) {
this.attachments = null; this.attachments = null;
this.container = options.container; this.container = options.container;
this.eventBus = options.eventBus;
this.downloadManager = options.downloadManager; this.downloadManager = options.downloadManager;
} }
@ -66,11 +68,10 @@ var PDFAttachmentViewer = (function PDFAttachmentViewerClosure() {
*/ */
_dispatchEvent: _dispatchEvent:
function PDFAttachmentViewer_dispatchEvent(attachmentsCount) { function PDFAttachmentViewer_dispatchEvent(attachmentsCount) {
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('attachmentsloaded', {
event.initCustomEvent('attachmentsloaded', true, true, { source: this,
attachmentsCount: attachmentsCount attachmentsCount: attachmentsCount
}); });
this.container.dispatchEvent(event);
}, },
/** /**

View File

@ -51,6 +51,7 @@ var PDFFindBar = (function PDFFindBarClosure() {
this.findPreviousButton = options.findPreviousButton || null; this.findPreviousButton = options.findPreviousButton || null;
this.findNextButton = options.findNextButton || null; this.findNextButton = options.findNextButton || null;
this.findController = options.findController || null; this.findController = options.findController || null;
this.eventBus = options.eventBus;
if (this.findController === null) { if (this.findController === null) {
throw new Error('PDFFindBar cannot be used without a ' + throw new Error('PDFFindBar cannot be used without a ' +
@ -103,14 +104,14 @@ var PDFFindBar = (function PDFFindBarClosure() {
}, },
dispatchEvent: function PDFFindBar_dispatchEvent(type, findPrev) { dispatchEvent: function PDFFindBar_dispatchEvent(type, findPrev) {
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('find', {
event.initCustomEvent('find' + type, true, true, { source: this,
type: type,
query: this.findField.value, query: this.findField.value,
caseSensitive: this.caseSensitive.checked, caseSensitive: this.caseSensitive.checked,
highlightAll: this.highlightAll.checked, highlightAll: this.highlightAll.checked,
findPrevious: findPrev findPrevious: findPrev
}); });
return window.dispatchEvent(event);
}, },
updateUIState: updateUIState:

View File

@ -71,22 +71,6 @@ var PDFFindController = (function PDFFindControllerClosure() {
} }
PDFFindController.prototype = { PDFFindController.prototype = {
listenWindowEvents: function PDFFindController_listenWindowEvents() {
var events = [
'find',
'findagain',
'findhighlightallchange',
'findcasesensitivitychange'
];
var handleEvent = function (e) {
this.executeCommand(e.type, e.detail);
}.bind(this);
for (var i = 0, len = events.length; i < len; i++) {
window.addEventListener(events[i], handleEvent);
}
},
reset: function PDFFindController_reset() { reset: function PDFFindController_reset() {
this.startedTextExtraction = false; this.startedTextExtraction = false;
this.extractTextPromises = []; this.extractTextPromises = [];

View File

@ -17,16 +17,18 @@
(function (root, factory) { (function (root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define('pdfjs-web/pdf_history', ['exports'], factory); define('pdfjs-web/pdf_history', ['exports', 'pdfjs-web/dom_events'],
factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports); factory(exports, require('./dom_events.js'));
} else { } else {
factory((root.pdfjsWebPDFHistory = {})); factory((root.pdfjsWebPDFHistory = {}), root.pdfjsWebDOMEvents);
} }
}(this, function (exports) { }(this, function (exports, domEvents) {
function PDFHistory(options) { function PDFHistory(options) {
this.linkService = options.linkService; this.linkService = options.linkService;
this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
this.initialized = false; this.initialized = false;
this.initialDestination = null; this.initialDestination = null;
@ -173,8 +175,8 @@
window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false); window.addEventListener('beforeunload', pdfHistoryBeforeUnload, false);
}, false); }, false);
window.addEventListener('presentationmodechanged', function(e) { self.eventBus.on('presentationmodechanged', function(e) {
self.isViewerInPresentationMode = !!e.detail.active; self.isViewerInPresentationMode = e.active;
}); });
}, },

View File

@ -17,17 +17,23 @@
(function (root, factory) { (function (root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define('pdfjs-web/pdf_link_service', ['exports', 'pdfjs-web/ui_utils'], define('pdfjs-web/pdf_link_service', ['exports', 'pdfjs-web/ui_utils',
factory); 'pdfjs-web/dom_events'], factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js')); factory(exports, require('./ui_utils.js'), require('./dom_events.js'));
} else { } else {
factory((root.pdfjsWebPDFLinkService = {}), root.pdfjsWebUIUtils); factory((root.pdfjsWebPDFLinkService = {}), root.pdfjsWebUIUtils,
root.pdfjsWebDOMEvents);
} }
}(this, function (exports, uiUtils) { }(this, function (exports, uiUtils, domEvents) {
var parseQueryString = uiUtils.parseQueryString; var parseQueryString = uiUtils.parseQueryString;
/**
* @typedef {Object} PDFLinkServiceOptions
* @property {EventBus} eventBus - The application event bus.
*/
/** /**
* Performs navigation functions inside PDF, such as opening specified page, * Performs navigation functions inside PDF, such as opening specified page,
* or destination. * or destination.
@ -37,8 +43,11 @@ var parseQueryString = uiUtils.parseQueryString;
var PDFLinkService = (function () { var PDFLinkService = (function () {
/** /**
* @constructs PDFLinkService * @constructs PDFLinkService
* @param {PDFLinkServiceOptions} options
*/ */
function PDFLinkService() { function PDFLinkService(options) {
options = options || {};
this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
this.baseUrl = null; this.baseUrl = null;
this.pdfDocument = null; this.pdfDocument = null;
this.pdfViewer = null; this.pdfViewer = null;
@ -238,11 +247,10 @@ var PDFLinkService = (function () {
this.page = pageNumber; // simple page this.page = pageNumber; // simple page
} }
if ('pagemode' in params) { if ('pagemode' in params) {
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('pagemode', {
event.initCustomEvent('pagemode', true, true, { source: this,
mode: params.pagemode, mode: params.pagemode
}); });
this.pdfViewer.container.dispatchEvent(event);
} }
} else if (/^\d+$/.test(hash)) { // page number } else if (/^\d+$/.test(hash)) { // page number
this.page = hash; this.page = hash;
@ -292,11 +300,10 @@ var PDFLinkService = (function () {
break; // No action according to spec break; // No action according to spec
} }
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('namedaction', {
event.initCustomEvent('namedaction', true, true, { source: this,
action: action action: action
}); });
this.pdfViewer.container.dispatchEvent(event);
}, },
/** /**

View File

@ -32,6 +32,7 @@ var DEFAULT_TITLE = '\u2013';
* @typedef {Object} PDFOutlineViewerOptions * @typedef {Object} PDFOutlineViewerOptions
* @property {HTMLDivElement} container - The viewer element. * @property {HTMLDivElement} container - The viewer element.
* @property {IPDFLinkService} linkService - The navigation/linking service. * @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {EventBus} eventBus - The application event bus.
*/ */
/** /**
@ -52,6 +53,7 @@ var PDFOutlineViewer = (function PDFOutlineViewerClosure() {
this.lastToggleIsShow = true; this.lastToggleIsShow = true;
this.container = options.container; this.container = options.container;
this.linkService = options.linkService; this.linkService = options.linkService;
this.eventBus = options.eventBus;
} }
PDFOutlineViewer.prototype = { PDFOutlineViewer.prototype = {
@ -69,11 +71,10 @@ var PDFOutlineViewer = (function PDFOutlineViewerClosure() {
* @private * @private
*/ */
_dispatchEvent: function PDFOutlineViewer_dispatchEvent(outlineCount) { _dispatchEvent: function PDFOutlineViewer_dispatchEvent(outlineCount) {
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('outlineloaded', {
event.initCustomEvent('outlineloaded', true, true, { source: this,
outlineCount: outlineCount outlineCount: outlineCount
}); });
this.container.dispatchEvent(event);
}, },
/** /**

View File

@ -19,15 +19,17 @@
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define('pdfjs-web/pdf_page_view', ['exports', define('pdfjs-web/pdf_page_view', ['exports',
'pdfjs-web/ui_utils', 'pdfjs-web/pdf_rendering_queue', 'pdfjs-web/ui_utils', 'pdfjs-web/pdf_rendering_queue',
'pdfjs-web/pdfjs'], factory); 'pdfjs-web/dom_events', 'pdfjs-web/pdfjs'], factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'), factory(exports, require('./ui_utils.js'),
require('./pdf_rendering_queue.js'), require('./pdfjs.js')); require('./pdf_rendering_queue.js'), require('./dom_events.js'),
require('./pdfjs.js'));
} else { } else {
factory((root.pdfjsWebPDFPageView = {}), root.pdfjsWebUIUtils, factory((root.pdfjsWebPDFPageView = {}), root.pdfjsWebUIUtils,
root.pdfjsWebPDFRenderingQueue, root.pdfjsWebPDFJS); root.pdfjsWebPDFRenderingQueue, root.pdfjsWebDOMEvents,
root.pdfjsWebPDFJS);
} }
}(this, function (exports, uiUtils, pdfRenderingQueue, pdfjsLib) { }(this, function (exports, uiUtils, pdfRenderingQueue, domEvents, pdfjsLib) {
var CSS_UNITS = uiUtils.CSS_UNITS; var CSS_UNITS = uiUtils.CSS_UNITS;
var DEFAULT_SCALE = uiUtils.DEFAULT_SCALE; var DEFAULT_SCALE = uiUtils.DEFAULT_SCALE;
@ -41,6 +43,7 @@ var TEXT_LAYER_RENDER_DELAY = 200; // ms
/** /**
* @typedef {Object} PDFPageViewOptions * @typedef {Object} PDFPageViewOptions
* @property {HTMLDivElement} container - The viewer element. * @property {HTMLDivElement} container - The viewer element.
* @property {EventBus} eventBus - The application event bus.
* @property {number} id - The page unique ID (normally its number). * @property {number} id - The page unique ID (normally its number).
* @property {number} scale - The page scale display. * @property {number} scale - The page scale display.
* @property {PageViewport} defaultViewport - The page viewport. * @property {PageViewport} defaultViewport - The page viewport.
@ -76,6 +79,7 @@ var PDFPageView = (function PDFPageViewClosure() {
this.pdfPageRotate = defaultViewport.rotation; this.pdfPageRotate = defaultViewport.rotation;
this.hasRestrictedScaling = false; this.hasRestrictedScaling = false;
this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
this.renderingQueue = renderingQueue; this.renderingQueue = renderingQueue;
this.textLayerFactory = textLayerFactory; this.textLayerFactory = textLayerFactory;
this.annotationLayerFactory = annotationLayerFactory; this.annotationLayerFactory = annotationLayerFactory;
@ -196,13 +200,11 @@ var PDFPageView = (function PDFPageViewClosure() {
(this.hasRestrictedScaling && isScalingRestricted)) { (this.hasRestrictedScaling && isScalingRestricted)) {
this.cssTransform(this.canvas, true); this.cssTransform(this.canvas, true);
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('pagerendered', {
event.initCustomEvent('pagerendered', true, true, { source: this,
pageNumber: this.id, pageNumber: this.id,
cssTransform: true, cssTransform: true,
}); });
this.div.dispatchEvent(event);
return; return;
} }
if (!this.zoomLayer) { if (!this.zoomLayer) {
@ -450,12 +452,11 @@ var PDFPageView = (function PDFPageViewClosure() {
if (self.onAfterDraw) { if (self.onAfterDraw) {
self.onAfterDraw(); self.onAfterDraw();
} }
var event = document.createEvent('CustomEvent'); self.eventBus.dispatch('pagerendered', {
event.initCustomEvent('pagerendered', true, true, { source: self,
pageNumber: self.id, pageNumber: self.id,
cssTransform: false, cssTransform: false,
}); });
div.dispatchEvent(event);
if (!error) { if (!error) {
resolveRenderPromise(undefined); resolveRenderPromise(undefined);

View File

@ -35,6 +35,7 @@ var CONTROLS_SELECTOR = 'pdfPresentationModeControls';
* @property {HTMLDivElement} container - The container for the viewer element. * @property {HTMLDivElement} container - The container for the viewer element.
* @property {HTMLDivElement} viewer - (optional) The viewer element. * @property {HTMLDivElement} viewer - (optional) The viewer element.
* @property {PDFViewer} pdfViewer - The document viewer. * @property {PDFViewer} pdfViewer - The document viewer.
* @property {EventBus} eventBus - The application event bus.
* @property {Array} contextMenuItems - (optional) The menuitems that are added * @property {Array} contextMenuItems - (optional) The menuitems that are added
* to the context menu in Presentation Mode. * to the context menu in Presentation Mode.
*/ */
@ -51,6 +52,7 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
this.container = options.container; this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild; this.viewer = options.viewer || options.container.firstElementChild;
this.pdfViewer = options.pdfViewer; this.pdfViewer = options.pdfViewer;
this.eventBus = options.eventBus;
var contextMenuItems = options.contextMenuItems || null; var contextMenuItems = options.contextMenuItems || null;
this.active = false; this.active = false;
@ -163,12 +165,11 @@ var PDFPresentationMode = (function PDFPresentationModeClosure() {
* @private * @private
*/ */
_notifyStateChange: function PDFPresentationMode_notifyStateChange() { _notifyStateChange: function PDFPresentationMode_notifyStateChange() {
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('presentationmodechanged', {
event.initCustomEvent('presentationmodechanged', true, true, { source: this,
active: this.active, active: this.active,
switchInProgress: !!this.switchInProgress switchInProgress: !!this.switchInProgress
}); });
window.dispatchEvent(event);
}, },
/** /**

View File

@ -44,6 +44,7 @@ var SidebarView = {
* (in which the viewer element is placed). * (in which the viewer element is placed).
* @property {HTMLDivElement} outerContainer - The outer container * @property {HTMLDivElement} outerContainer - The outer container
* (encasing both the viewer and sidebar elements). * (encasing both the viewer and sidebar elements).
* @property {EventBus} eventBus - The application event bus.
* @property {HTMLButtonElement} toggleButton - The button used for * @property {HTMLButtonElement} toggleButton - The button used for
* opening/closing the sidebar. * opening/closing the sidebar.
* @property {HTMLButtonElement} thumbnailButton - The button used to show * @property {HTMLButtonElement} thumbnailButton - The button used to show
@ -85,6 +86,7 @@ var PDFSidebar = (function PDFSidebarClosure() {
this.mainContainer = options.mainContainer; this.mainContainer = options.mainContainer;
this.outerContainer = options.outerContainer; this.outerContainer = options.outerContainer;
this.eventBus = options.eventBus;
this.toggleButton = options.toggleButton; this.toggleButton = options.toggleButton;
this.thumbnailButton = options.thumbnailButton; this.thumbnailButton = options.thumbnailButton;
@ -272,11 +274,10 @@ var PDFSidebar = (function PDFSidebarClosure() {
* @private * @private
*/ */
_dispatchEvent: function PDFSidebar_dispatchEvent() { _dispatchEvent: function PDFSidebar_dispatchEvent() {
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('sidebarviewchanged', {
event.initCustomEvent('sidebarviewchanged', true, true, { source: this,
view: this.visibleView, view: this.visibleView
}); });
this.outerContainer.dispatchEvent(event);
}, },
/** /**
@ -339,8 +340,8 @@ var PDFSidebar = (function PDFSidebarClosure() {
}); });
// Disable/enable views. // Disable/enable views.
self.outlineView.addEventListener('outlineloaded', function(evt) { self.eventBus.on('outlineloaded', function(e) {
var outlineCount = evt.detail.outlineCount; var outlineCount = e.outlineCount;
self.outlineButton.disabled = !outlineCount; self.outlineButton.disabled = !outlineCount;
if (!outlineCount && self.active === SidebarView.OUTLINE) { if (!outlineCount && self.active === SidebarView.OUTLINE) {
@ -348,8 +349,8 @@ var PDFSidebar = (function PDFSidebarClosure() {
} }
}); });
self.attachmentsView.addEventListener('attachmentsloaded', function(evt) { self.eventBus.on('attachmentsloaded', function(e) {
var attachmentsCount = evt.detail.attachmentsCount; var attachmentsCount = e.attachmentsCount;
self.attachmentsButton.disabled = !attachmentsCount; self.attachmentsButton.disabled = !attachmentsCount;
if (!attachmentsCount && self.active === SidebarView.ATTACHMENTS) { if (!attachmentsCount && self.active === SidebarView.ATTACHMENTS) {
@ -358,9 +359,8 @@ var PDFSidebar = (function PDFSidebarClosure() {
}); });
// Update the thumbnailViewer, if visible, when exiting presentation mode. // Update the thumbnailViewer, if visible, when exiting presentation mode.
window.addEventListener('presentationmodechanged', function(evt) { self.eventBus.on('presentationmodechanged', function(e) {
if (!evt.detail.active && !evt.detail.switchInProgress && if (!e.active && !e.switchInProgress && self.isThumbnailViewVisible) {
self.isThumbnailViewVisible) {
self._updateThumbnailViewer(); self._updateThumbnailViewer();
} }
}); });

View File

@ -52,6 +52,7 @@
PDFJS.PDFHistory = pdfViewerLibs.pdfjsWebPDFHistory.PDFHistory; PDFJS.PDFHistory = pdfViewerLibs.pdfjsWebPDFHistory.PDFHistory;
PDFJS.PDFFindController = PDFJS.PDFFindController =
pdfViewerLibs.pdfjsWebPDFFindController.PDFFindController; pdfViewerLibs.pdfjsWebPDFFindController.PDFFindController;
PDFJS.EventBus = pdfViewerLibs.pdfjsWebUIUtils.EventBus;
PDFJS.DownloadManager = pdfViewerLibs.pdfjsWebDownloadManager.DownloadManager; PDFJS.DownloadManager = pdfViewerLibs.pdfjsWebDownloadManager.DownloadManager;
PDFJS.ProgressBar = pdfViewerLibs.pdfjsWebUIUtils.ProgressBar; PDFJS.ProgressBar = pdfViewerLibs.pdfjsWebUIUtils.ProgressBar;

View File

@ -20,21 +20,23 @@
define('pdfjs-web/pdf_viewer', ['exports', 'pdfjs-web/ui_utils', define('pdfjs-web/pdf_viewer', ['exports', 'pdfjs-web/ui_utils',
'pdfjs-web/pdf_page_view', 'pdfjs-web/pdf_rendering_queue', 'pdfjs-web/pdf_page_view', 'pdfjs-web/pdf_rendering_queue',
'pdfjs-web/text_layer_builder', 'pdfjs-web/annotation_layer_builder', 'pdfjs-web/text_layer_builder', 'pdfjs-web/annotation_layer_builder',
'pdfjs-web/pdf_link_service', 'pdfjs-web/pdfjs'], factory); 'pdfjs-web/pdf_link_service', 'pdfjs-web/dom_events', 'pdfjs-web/pdfjs'],
factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('./ui_utils.js'), require('./pdf_page_view.js'), factory(exports, require('./ui_utils.js'), require('./pdf_page_view.js'),
require('./pdf_rendering_queue.js'), require('./text_layer_builder.js'), require('./pdf_rendering_queue.js'), require('./text_layer_builder.js'),
require('./annotation_layer_builder.js'), require('./annotation_layer_builder.js'),
require('./pdf_link_service.js'), require('./pdfjs.js')); require('./pdf_link_service.js'), require('./dom_events.js'),
require('./pdfjs.js'));
} else { } else {
factory((root.pdfjsWebPDFViewer = {}), root.pdfjsWebUIUtils, factory((root.pdfjsWebPDFViewer = {}), root.pdfjsWebUIUtils,
root.pdfjsWebPDFPageView, root.pdfjsWebPDFRenderingQueue, root.pdfjsWebPDFPageView, root.pdfjsWebPDFRenderingQueue,
root.pdfjsWebTextLayerBuilder, root.pdfjsWebAnnotationLayerBuilder, root.pdfjsWebTextLayerBuilder, root.pdfjsWebAnnotationLayerBuilder,
root.pdfjsWebPDFLinkService, root.pdfjsWebPDFJS); root.pdfjsWebPDFLinkService, root.pdfjsWebDOMEvents, root.pdfjsWebPDFJS);
} }
}(this, function (exports, uiUtils, pdfPageView, pdfRenderingQueue, }(this, function (exports, uiUtils, pdfPageView, pdfRenderingQueue,
textLayerBuilder, annotationLayerBuilder, pdfLinkService, textLayerBuilder, annotationLayerBuilder, pdfLinkService,
pdfjsLib) { domEvents, pdfjsLib) {
var UNKNOWN_SCALE = uiUtils.UNKNOWN_SCALE; var UNKNOWN_SCALE = uiUtils.UNKNOWN_SCALE;
var SCROLLBAR_PADDING = uiUtils.SCROLLBAR_PADDING; var SCROLLBAR_PADDING = uiUtils.SCROLLBAR_PADDING;
@ -66,6 +68,7 @@ var DEFAULT_CACHE_SIZE = 10;
* @typedef {Object} PDFViewerOptions * @typedef {Object} PDFViewerOptions
* @property {HTMLDivElement} container - The container for the viewer element. * @property {HTMLDivElement} container - The container for the viewer element.
* @property {HTMLDivElement} viewer - (optional) The viewer element. * @property {HTMLDivElement} viewer - (optional) The viewer element.
* @property {EventBus} eventBus - The application event bus.
* @property {IPDFLinkService} linkService - The navigation/linking service. * @property {IPDFLinkService} linkService - The navigation/linking service.
* @property {DownloadManager} downloadManager - (optional) The download * @property {DownloadManager} downloadManager - (optional) The download
* manager component. * manager component.
@ -120,6 +123,7 @@ var PDFViewer = (function pdfViewer() {
function PDFViewer(options) { function PDFViewer(options) {
this.container = options.container; this.container = options.container;
this.viewer = options.viewer || options.container.firstElementChild; this.viewer = options.viewer || options.container.firstElementChild;
this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
this.linkService = options.linkService || new SimpleLinkService(); this.linkService = options.linkService || new SimpleLinkService();
this.downloadManager = options.downloadManager || null; this.downloadManager = options.downloadManager || null;
this.removePageBorders = options.removePageBorders || false; this.removePageBorders = options.removePageBorders || false;
@ -162,21 +166,23 @@ var PDFViewer = (function pdfViewer() {
return; return;
} }
var event = document.createEvent('UIEvents');
event.initUIEvent('pagechange', true, true, window, 0);
event.updateInProgress = this.updateInProgress;
if (!(0 < val && val <= this.pagesCount)) { if (!(0 < val && val <= this.pagesCount)) {
event.pageNumber = this._currentPageNumber; this.eventBus.dispatch('pagechange', {
event.previousPageNumber = val; source: this,
this.container.dispatchEvent(event); updateInProgress: this.updateInProgress,
pageNumber: this._currentPageNumber,
previousPageNumber: val
});
return; return;
} }
event.previousPageNumber = this._currentPageNumber; this.eventBus.dispatch('pagechange', {
source: this,
updateInProgress: this.updateInProgress,
pageNumber: val,
previousPageNumber: this._currentPageNumber
});
this._currentPageNumber = val; this._currentPageNumber = val;
event.pageNumber = val;
this.container.dispatchEvent(event);
// Check if the caller is `PDFViewer_update`, to avoid breaking scrolling. // Check if the caller is `PDFViewer_update`, to avoid breaking scrolling.
if (this.updateInProgress) { if (this.updateInProgress) {
@ -274,11 +280,10 @@ var PDFViewer = (function pdfViewer() {
}); });
this.pagesPromise = pagesPromise; this.pagesPromise = pagesPromise;
pagesPromise.then(function () { pagesPromise.then(function () {
var event = document.createEvent('CustomEvent'); self.eventBus.dispatch('pagesloaded', {
event.initCustomEvent('pagesloaded', true, true, { source: self,
pagesCount: pagesCount pagesCount: pagesCount
}); });
self.container.dispatchEvent(event);
}); });
var isOnePageRenderedResolved = false; var isOnePageRenderedResolved = false;
@ -319,6 +324,7 @@ var PDFViewer = (function pdfViewer() {
} }
var pageView = new PDFPageView({ var pageView = new PDFPageView({
container: this.viewer, container: this.viewer,
eventBus: this.eventBus,
id: pageNum, id: pageNum,
scale: scale, scale: scale,
defaultViewport: viewport.clone(), defaultViewport: viewport.clone(),
@ -357,9 +363,7 @@ var PDFViewer = (function pdfViewer() {
} }
}); });
var event = document.createEvent('CustomEvent'); self.eventBus.dispatch('pagesinit', {source: self});
event.initCustomEvent('pagesinit', true, true, null);
self.container.dispatchEvent(event);
if (this.defaultRenderingQueue) { if (this.defaultRenderingQueue) {
this.update(); this.update();
@ -399,13 +403,11 @@ var PDFViewer = (function pdfViewer() {
_setScaleDispatchEvent: function pdfViewer_setScaleDispatchEvent( _setScaleDispatchEvent: function pdfViewer_setScaleDispatchEvent(
newScale, newValue, preset) { newScale, newValue, preset) {
var event = document.createEvent('UIEvents'); this.eventBus.dispatch('scalechange', {
event.initUIEvent('scalechange', true, true, window, 0); source: this,
event.scale = newScale; scale: newScale,
if (preset) { presetValue: preset ? newValue : undefined
event.presetValue = newValue; });
}
this.container.dispatchEvent(event);
}, },
_setScaleUpdatePages: function pdfViewer_setScaleUpdatePages( _setScaleUpdatePages: function pdfViewer_setScaleUpdatePages(
@ -671,10 +673,10 @@ var PDFViewer = (function pdfViewer() {
this.updateInProgress = false; this.updateInProgress = false;
var event = document.createEvent('UIEvents'); this.eventBus.dispatch('updateviewarea', {
event.initUIEvent('updateviewarea', true, true, window, 0); source: this,
event.location = this._location; location: this._location
this.container.dispatchEvent(event); });
}, },
containsElement: function (element) { containsElement: function (element) {
@ -772,6 +774,7 @@ var PDFViewer = (function pdfViewer() {
createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) { createTextLayerBuilder: function (textLayerDiv, pageIndex, viewport) {
return new TextLayerBuilder({ return new TextLayerBuilder({
textLayerDiv: textLayerDiv, textLayerDiv: textLayerDiv,
eventBus: this.eventBus,
pageIndex: pageIndex, pageIndex: pageIndex,
viewport: viewport, viewport: viewport,
findController: this.isInPresentationMode ? null : this.findController findController: this.isInPresentationMode ? null : this.findController

View File

@ -17,18 +17,21 @@
(function (root, factory) { (function (root, factory) {
if (typeof define === 'function' && define.amd) { if (typeof define === 'function' && define.amd) {
define('pdfjs-web/text_layer_builder', ['exports', 'pdfjs-web/pdfjs'], define('pdfjs-web/text_layer_builder', ['exports', 'pdfjs-web/dom_events',
'pdfjs-web/pdfjs'],
factory); factory);
} else if (typeof exports !== 'undefined') { } else if (typeof exports !== 'undefined') {
factory(exports, require('./pdfjs.js')); factory(exports, require('./dom_events.js'), require('./pdfjs.js'));
} else { } else {
factory((root.pdfjsWebTextLayerBuilder = {}), root.pdfjsWebPDFJS); factory((root.pdfjsWebTextLayerBuilder = {}), root.pdfjsWebDOMEvents,
root.pdfjsWebPDFJS);
} }
}(this, function (exports, pdfjsLib) { }(this, function (exports, domEvents, pdfjsLib) {
/** /**
* @typedef {Object} TextLayerBuilderOptions * @typedef {Object} TextLayerBuilderOptions
* @property {HTMLDivElement} textLayerDiv - The text layer container. * @property {HTMLDivElement} textLayerDiv - The text layer container.
* @property {EventBus} eventBus - The application event bus.
* @property {number} pageIndex - The page index. * @property {number} pageIndex - The page index.
* @property {PageViewport} viewport - The viewport of the text layer. * @property {PageViewport} viewport - The viewport of the text layer.
* @property {PDFFindController} findController * @property {PDFFindController} findController
@ -44,6 +47,7 @@
var TextLayerBuilder = (function TextLayerBuilderClosure() { var TextLayerBuilder = (function TextLayerBuilderClosure() {
function TextLayerBuilder(options) { function TextLayerBuilder(options) {
this.textLayerDiv = options.textLayerDiv; this.textLayerDiv = options.textLayerDiv;
this.eventBus = options.eventBus || domEvents.getGlobalEventBus();
this.renderingDone = false; this.renderingDone = false;
this.divContentDone = false; this.divContentDone = false;
this.pageIdx = options.pageIndex; this.pageIdx = options.pageIndex;
@ -64,11 +68,10 @@ var TextLayerBuilder = (function TextLayerBuilderClosure() {
endOfContent.className = 'endOfContent'; endOfContent.className = 'endOfContent';
this.textLayerDiv.appendChild(endOfContent); this.textLayerDiv.appendChild(endOfContent);
var event = document.createEvent('CustomEvent'); this.eventBus.dispatch('textlayerrendered', {
event.initCustomEvent('textlayerrendered', true, true, { source: this,
pageNumber: this.pageNumber pageNumber: this.pageNumber
}); });
this.textLayerDiv.dispatchEvent(event);
}, },
/** /**

View File

@ -384,6 +384,49 @@ function getPDFFileNameFromURL(url) {
return suggestedFilename || 'document.pdf'; return suggestedFilename || 'document.pdf';
} }
/**
* Simple event bus for an application. Listeners are attached using the
* `on` and `off` methods. To raise an event, the `dispatch` method shall be
* used.
*/
var EventBus = (function EventBusClosure() {
function EventBus() {
this._listeners = Object.create(null);
}
EventBus.prototype = {
on: function EventBus_on(eventName, listener) {
var eventListeners = this._listeners[eventName];
if (!eventListeners) {
eventListeners = [];
this._listeners[eventName] = eventListeners;
}
eventListeners.push(listener);
},
off: function EventBus_on(eventName, listener) {
var eventListeners = this._listeners[eventName];
var i;
if (!eventListeners || ((i = eventListeners.indexOf(listener)) < 0)) {
return;
}
eventListeners.splice(i, 1);
},
dispatch: function EventBus_dispath(eventName) {
var eventListeners = this._listeners[eventName];
if (!eventListeners || eventListeners.length === 0) {
return;
}
// Passing all arguments after the eventName to the listeners.
var args = Array.prototype.slice.call(arguments, 1);
// Making copy of the listeners array in case if it will be modified
// during dispatch.
eventListeners.slice(0).forEach(function (listener) {
listener.apply(null, args);
});
}
};
return EventBus;
})();
var ProgressBar = (function ProgressBarClosure() { var ProgressBar = (function ProgressBarClosure() {
function clamp(v, min, max) { function clamp(v, min, max) {
@ -474,6 +517,7 @@ exports.MAX_AUTO_SCALE = MAX_AUTO_SCALE;
exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING; exports.SCROLLBAR_PADDING = SCROLLBAR_PADDING;
exports.VERTICAL_PADDING = VERTICAL_PADDING; exports.VERTICAL_PADDING = VERTICAL_PADDING;
exports.mozL10n = mozL10n; exports.mozL10n = mozL10n;
exports.EventBus = EventBus;
exports.ProgressBar = ProgressBar; exports.ProgressBar = ProgressBar;
exports.getPDFFileNameFromURL = getPDFFileNameFromURL; exports.getPDFFileNameFromURL = getPDFFileNameFromURL;
exports.noContextMenuHandler = noContextMenuHandler; exports.noContextMenuHandler = noContextMenuHandler;

View File

@ -55,6 +55,7 @@ function getViewerConfiguration() {
appContainer: document.body, appContainer: document.body,
mainContainer: document.getElementById('viewerContainer'), mainContainer: document.getElementById('viewerContainer'),
viewerContainer: document.getElementById('viewer'), viewerContainer: document.getElementById('viewer'),
eventBus: null, // using global event bus with DOM events
toolbar: { toolbar: {
numPages: document.getElementById('numPages'), numPages: document.getElementById('numPages'),
pageNumber: document.getElementById('pageNumber'), pageNumber: document.getElementById('pageNumber'),