Skip to content

Commit

Permalink
Chore: Refactor pageControls and scroll handling for multi page images (
Browse files Browse the repository at this point in the history
#321)

* Chore: Refactor pageControls and scroll handling for multi page images

* Chore: fix conflicts, tests, and small changes
  • Loading branch information
Jeremy Press authored Aug 29, 2017
1 parent 75b183d commit f9f511e
Show file tree
Hide file tree
Showing 12 changed files with 542 additions and 245 deletions.
1 change: 1 addition & 0 deletions src/lib/Controls.scss
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
margin: 0;
padding: 0;
touch-action: manipulation;
user-select: none;
vertical-align: middle;
}

Expand Down
170 changes: 115 additions & 55 deletions src/lib/PageControls.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,71 @@ const pageNumTemplate = `
</div>`.replace(/>\s*</g, '><');

class PageControls extends EventEmitter {
/** @property {Controls} - Controls object */
controls;

/** @property {HTMLElement} - Controls element */
controlsEl;

/** @property {HTMLElement} - File content element */
contentEl;

/** @property {HTMLElement} - Total pages element */
totalPagesEl;

/** @property {HTMLElement} - Current page element */
currentPageEl;

/** @property {HTMLElement} - Page number input element */
pageNumInputEl;
/**
* [constructor]
*
* @param {HTMLElement} controls - Viewer controls
* @param {Function} previousPage - Previous page handler
* @param {Function} nextPage - Next page handler
* @param {HTMLElement} contentEl - The content element of the file
* @return {Controls} Instance of controls
*/
constructor(controls, previousPage, nextPage) {
constructor(controls, contentEl) {
super();

this.controls = controls;
this.controlsEl = controls.controlsEl;
this.currentPageEl = controls.currentPageEl;
this.pageNumInputEl = controls.pageNumInputEl;
this.previousPage = previousPage;
this.nextPage = nextPage;

this.contentEl = contentEl;

this.pageNumInputBlurHandler = this.pageNumInputBlurHandler.bind(this);
this.pageNumInputKeydownHandler = this.pageNumInputKeydownHandler.bind(this);
this.setPreviousPage = this.setPreviousPage.bind(this);
this.showPageNumInput = this.showPageNumInput.bind(this);
this.setNextPage = this.setNextPage.bind(this);
}

/**
* Adds controls and initializes page number selector.
* Add the page controls
*
* @private
* @param {number} pagesCount - Total number of page
* @param {number} currentPageNumber - Current page number
* @param {number} pagesCount - Number of total pages
* @return {void}
*/
init(pagesCount) {
// Add controls
this.controls.add(__('previous_page'), this.previousPage, `bp-previous-page-icon ${PREV_PAGE}`, ICON_DROP_UP);
this.controls.add(__('enter_page_num'), this.showPageNumInput.bind(this), PAGE_NUM, pageNumTemplate);
this.controls.add(__('next_page'), this.nextPage, `bp-next-page-icon ${NEXT_PAGE}`, ICON_DROP_DOWN);
add(currentPageNumber, pagesCount) {
this.controls.add(
__('previous_page'),
this.setPreviousPage,
`bp-previous-page-icon ${PREV_PAGE}`,
ICON_DROP_UP
);
this.controls.add(__('enter_page_num'), this.showPageNumInput, PAGE_NUM, pageNumTemplate);
this.controls.add(__('next_page'), this.setNextPage, `bp-next-page-icon ${NEXT_PAGE}`, ICON_DROP_DOWN);

// Initialize page number selector
const pageNumEl = this.controlsEl.querySelector(`.${PAGE_NUM}`);
this.pagesCount = pagesCount;

// Update total page number
const totalPageEl = pageNumEl.querySelector(`.${CONTROLS_TOTAL_PAGES}`);
totalPageEl.textContent = pagesCount;

// Keep reference to page number input and current page elements
this.totalPagesEl = pageNumEl.querySelector(`.${CONTROLS_TOTAL_PAGES}`);
this.totalPagesEl.textContent = pagesCount;
this.currentPageEl = pageNumEl.querySelector(`.${CONTROLS_CURRENT_PAGE}`);
this.currentPageEl.textContent = currentPageNumber;
this.pageNumInputEl = pageNumEl.querySelector(`.${CONTROLS_PAGE_NUM_INPUT_CLASS}`);
this.pageNumInputEl.setAttribute('max', pagesCount);

this.currentPageEl = pageNumEl.querySelector(`.${CONTROLS_CURRENT_PAGE}`);
this.checkPaginationButtons();
}

/**
Expand All @@ -79,13 +99,13 @@ class PageControls extends EventEmitter {
// show the input box with the current page number selected within it
this.controlsEl.classList.add(SHOW_PAGE_NUM_INPUT_CLASS);

this.pageNumInputEl.value = this.currentPageEl.textContent;
this.pageNumInputEl.value = this.getCurrentPageNumber();
this.pageNumInputEl.focus();
this.pageNumInputEl.select();

// finish input when input is blurred or enter key is pressed
this.pageNumInputEl.addEventListener('blur', this.pageNumInputBlurHandler.bind(this));
this.pageNumInputEl.addEventListener('keydown', this.pageNumInputKeydownHandler.bind(this));
this.pageNumInputEl.addEventListener('blur', this.pageNumInputBlurHandler);
this.pageNumInputEl.addEventListener('keydown', this.pageNumInputKeydownHandler);
}

/**
Expand All @@ -104,11 +124,9 @@ class PageControls extends EventEmitter {
* Disables or enables previous/next pagination buttons depending on
* current page number.
*
* @param {number} currentPageNum - Current page number
* @param {number} pagesCount - Total number of page
* @return {void}
*/
checkPaginationButtons(currentPageNum, pagesCount) {
checkPaginationButtons() {
const pageNumButtonEl = this.controlsEl.querySelector(`.${PAGE_NUM}`);
const previousPageButtonEl = this.controlsEl.querySelector(`.${PREV_PAGE}`);
const nextPageButtonEl = this.controlsEl.querySelector(`.${NEXT_PAGE}`);
Expand All @@ -118,7 +136,7 @@ class PageControls extends EventEmitter {

// Disable page number selector if there is only one page or less
if (pageNumButtonEl) {
if (pagesCount <= 1 || isSafariFullscreen) {
if (this.getTotalPages() <= 1 || isSafariFullscreen) {
pageNumButtonEl.disabled = true;
} else {
pageNumButtonEl.disabled = false;
Expand All @@ -127,7 +145,7 @@ class PageControls extends EventEmitter {

// Disable previous page if on first page, otherwise enable
if (previousPageButtonEl) {
if (currentPageNum === 1) {
if (this.getCurrentPageNumber() === 1) {
previousPageButtonEl.disabled = true;
} else {
previousPageButtonEl.disabled = false;
Expand All @@ -136,7 +154,7 @@ class PageControls extends EventEmitter {

// Disable next page if on last page, otherwise enable
if (nextPageButtonEl) {
if (currentPageNum === pagesCount) {
if (this.getCurrentPageNumber() === this.getTotalPages()) {
nextPageButtonEl.disabled = true;
} else {
nextPageButtonEl.disabled = false;
Expand All @@ -147,30 +165,71 @@ class PageControls extends EventEmitter {
/**
* Update page number in page control widget.
*
* @private
* @param {number} pageNum - Number of page to update to
* @public
* @param {number} pageNumber - Number of page to update to
* @return {void}
*/
updateCurrentPage(pageNum) {
let truePageNum = pageNum;

// refine the page number to fall within bounds
if (pageNum > this.pagesCount) {
truePageNum = this.pagesCount;
} else if (pageNum < 1) {
truePageNum = 1;
}

updateCurrentPage(pageNumber) {
if (this.pageNumInputEl) {
this.pageNumInputEl.value = truePageNum;
this.pageNumInputEl.value = pageNumber;
}

if (this.currentPageEl) {
this.currentPageEl.textContent = truePageNum;
this.setCurrentPageNumber(pageNumber);
}

this.currentPageNumber = truePageNum;
this.checkPaginationButtons(this.currentPageNumber, this.pagesCount);
this.checkPaginationButtons();
}

/**
* Emits a message to the viewer to decrement the current page.
*
* @private
* @return {void}
*/
setPreviousPage() {
this.emit('pagechange', this.getCurrentPageNumber() - 1);
}

/**
* Emits a message to the viewer to increment the current page.
*
* @private
* @return {void}
*/
setNextPage() {
this.emit('pagechange', this.getCurrentPageNumber() + 1);
}

/**
* Gets the page number for the file.
*
* @private
* @return {number} Number of pages
*/
getCurrentPageNumber() {
return parseInt(this.currentPageEl.textContent, 10);
}

/**
* Sets the number of pages for the file.
*
* @private
* @param {number} pageNumber - Number to set
* @return {number} Number of pages
*/
setCurrentPageNumber(pageNumber) {
this.currentPageEl.textContent = pageNumber;
}

/**
* Gets the number of pages for the file.
*
* @private
* @return {number} Number of pages
*/
getTotalPages() {
return parseInt(this.totalPagesEl.textContent, 10);
}

/**
Expand All @@ -182,10 +241,10 @@ class PageControls extends EventEmitter {
*/
pageNumInputBlurHandler(event) {
const target = event.target;
const pageNum = parseInt(target.value, 10);
const pageNumber = parseInt(target.value, 10);

if (!isNaN(pageNum)) {
this.emit('setpage', pageNum);
if (!isNaN(pageNumber)) {
this.emit('pagechange', pageNumber);
}

this.hidePageNumInput();
Expand All @@ -204,12 +263,13 @@ class PageControls extends EventEmitter {
switch (key) {
case 'Enter':
case 'Tab':
this.contentEl.focus();
// The keycode of the 'next' key on Android Chrome is 9, which maps to 'Tab'.
// this.docEl.focus();
// We normally trigger the blur handler by blurring the input
// field, but this doesn't work for IE in fullscreen. For IE,
// we blur the page behind the controls - this unfortunately
// is an IE-only solution that doesn't work with other browsers

if (Browser.getName() !== 'Explorer') {
event.target.blur();
}
Expand All @@ -220,7 +280,7 @@ class PageControls extends EventEmitter {

case 'Escape':
this.hidePageNumInput();
// this.docEl.focus();
this.contentEl.focus();

event.stopPropagation();
event.preventDefault();
Expand Down
Loading

0 comments on commit f9f511e

Please sign in to comment.