From e8a3c573e496f565a96340551d9c71f84ccb9ad2 Mon Sep 17 00:00:00 2001 From: Jared Stoffan Date: Mon, 11 Jan 2021 18:15:38 -0800 Subject: [PATCH] feat(controls): Cleanup legacy controls from non-media viewers (#1312) --- src/lib/AnnotationControls.scss | 25 -- src/lib/AnnotationControls.ts | 224 ----------- src/lib/AnnotationControlsFSM.ts | 4 +- src/lib/Controls.js | 20 +- src/lib/Controls.scss | 61 --- src/lib/PageControls.js | 316 --------------- src/lib/Preview.js | 3 - src/lib/ZoomControls.js | 140 ------- src/lib/ZoomControls.scss | 6 - .../__tests__/AnnotationControls-test.html | 1 - src/lib/__tests__/AnnotationControls-test.js | 257 ------------ .../__tests__/AnnotationControlsFSM-test.js | 3 +- src/lib/__tests__/Controls-test.js | 27 -- src/lib/__tests__/PageControls-test.html | 1 - src/lib/__tests__/PageControls-test.js | 289 ------------- src/lib/__tests__/Preview-test.js | 13 - src/lib/__tests__/ZoomControls-test.html | 1 - src/lib/__tests__/ZoomControls-test.js | 194 --------- src/lib/icons/arrow_drop_down_24px.svg | 4 - src/lib/icons/arrow_drop_up_24px.svg | 4 - src/lib/icons/delete_24px.svg | 4 - src/lib/icons/highlight_text.svg | 1 - src/lib/icons/icons.js | 18 - src/lib/icons/region_comment.svg | 1 - src/lib/icons/rotate_left_24px.svg | 4 - src/lib/icons/zoom_in.svg | 1 - src/lib/icons/zoom_out.svg | 1 - .../types.ts => types/annotations.ts} | 0 src/lib/types/index.ts | 1 + src/lib/viewers/BaseViewer.js | 3 +- src/lib/viewers/__tests__/BaseViewer-test.js | 2 +- .../annotations/AnnotationsButton.tsx | 2 +- .../annotations/AnnotationsControls.tsx | 2 +- .../controls/annotations/DrawingControls.tsx | 2 +- .../__tests__/AnnotationsButton-test.tsx | 2 +- .../__tests__/AnnotationsControls-test.tsx | 2 +- .../__tests__/DrawingControls-test.tsx | 2 +- .../viewers/controls/zoom/ZoomControls.tsx | 2 +- .../zoom/__tests__/ZoomControls-test.tsx | 3 +- src/lib/viewers/doc/DocBaseViewer.js | 170 ++------ .../doc/__tests__/DocBaseViewer-test.js | 378 ++++-------------- src/lib/viewers/doc/_docBase.scss | 3 - src/lib/viewers/image/ImageBaseViewer.js | 20 +- src/lib/viewers/image/ImageViewer.js | 85 ++-- src/lib/viewers/image/MultiImageViewer.js | 70 +--- .../image/__tests__/ImageBaseViewer-test.js | 32 +- .../image/__tests__/ImageViewer-test.js | 66 +-- .../image/__tests__/MultiImageViewer-test.js | 84 +--- src/lib/viewers/media/MediaControls.js | 2 +- src/lib/viewers/text/CSVViewer.js | 7 +- src/lib/viewers/text/MarkdownViewer.js | 35 +- src/lib/viewers/text/PlainTextViewer.js | 11 +- src/lib/viewers/text/TextBaseViewer.js | 58 +-- .../viewers/text/__tests__/CSVViewer-test.js | 13 - .../text/__tests__/MarkdownViewer-test.js | 20 +- .../text/__tests__/PlainTextViewer-test.js | 13 - .../text/__tests__/TextBaseViewer-test.js | 54 +-- .../integration/document/Controls.e2e.test.js | 39 +- .../document/Thumbnails.e2e.test.js | 49 +-- .../sanity/FileOptions.e2e.test.js | 18 +- 60 files changed, 294 insertions(+), 2579 deletions(-) delete mode 100644 src/lib/AnnotationControls.scss delete mode 100644 src/lib/AnnotationControls.ts delete mode 100644 src/lib/PageControls.js delete mode 100644 src/lib/ZoomControls.js delete mode 100644 src/lib/ZoomControls.scss delete mode 100644 src/lib/__tests__/AnnotationControls-test.html delete mode 100644 src/lib/__tests__/AnnotationControls-test.js delete mode 100644 src/lib/__tests__/PageControls-test.html delete mode 100644 src/lib/__tests__/PageControls-test.js delete mode 100644 src/lib/__tests__/ZoomControls-test.html delete mode 100644 src/lib/__tests__/ZoomControls-test.js delete mode 100755 src/lib/icons/arrow_drop_down_24px.svg delete mode 100755 src/lib/icons/arrow_drop_up_24px.svg delete mode 100755 src/lib/icons/delete_24px.svg delete mode 100644 src/lib/icons/highlight_text.svg delete mode 100644 src/lib/icons/region_comment.svg delete mode 100755 src/lib/icons/rotate_left_24px.svg delete mode 100644 src/lib/icons/zoom_in.svg delete mode 100644 src/lib/icons/zoom_out.svg rename src/lib/{viewers/controls/annotations/types.ts => types/annotations.ts} (100%) create mode 100644 src/lib/types/index.ts diff --git a/src/lib/AnnotationControls.scss b/src/lib/AnnotationControls.scss deleted file mode 100644 index 82fa00af7..000000000 --- a/src/lib/AnnotationControls.scss +++ /dev/null @@ -1,25 +0,0 @@ -.bp-AnnotationControls-group { - padding-left: 4px; - border-left: 1px solid $twos; - - .bp-AnnotationControls-button { - svg { - width: 34px; - height: 32px; - padding: 4px 5px; - border-radius: 4px; - fill: $white; - } - - &.is-active { - svg { - background-color: $white; - fill: $black; - } - } - } - - &.is-hidden { - display: none; - } -} diff --git a/src/lib/AnnotationControls.ts b/src/lib/AnnotationControls.ts deleted file mode 100644 index cbf7da0d2..000000000 --- a/src/lib/AnnotationControls.ts +++ /dev/null @@ -1,224 +0,0 @@ -import noop from 'lodash/noop'; - -import { ICON_HIGHLIGHT_TEXT, ICON_REGION_COMMENT } from './icons/icons'; -import Controls from './Controls'; - -export const CLASS_ANNOTATIONS_BUTTON = 'bp-AnnotationControls-button'; -export const CLASS_ANNOTATIONS_GROUP = 'bp-AnnotationControls-group'; -export const CLASS_HIGHLIGHT_BUTTON = 'bp-AnnotationControls-highlightBtn'; -export const CLASS_REGION_BUTTON = 'bp-AnnotationControls-regionBtn'; - -export const CLASS_BUTTON_ACTIVE = 'is-active'; -export const CLASS_GROUP_HIDE = 'is-hidden'; - -export enum AnnotationMode { - DRAWING = 'drawing', - HIGHLIGHT = 'highlight', - NONE = 'none', - REGION = 'region', -} -export type ClickHandler = ({ event, mode }: { event: MouseEvent; mode: AnnotationMode }) => void; -export type Options = { - fileId: string; - initialMode?: AnnotationMode; - onClick?: ClickHandler; - onEscape?: () => void; - showHighlightText: boolean; -}; - -type ButtonProps = { - classname: string; - icon: string; - resinTarget: string; - testid: string; - text: string; -}; - -declare const __: (key: string) => string; - -const buttonClassMap: { [key: string]: string } = { - [AnnotationMode.HIGHLIGHT]: CLASS_HIGHLIGHT_BUTTON, - [AnnotationMode.REGION]: CLASS_REGION_BUTTON, -}; -const buttonPropsMap: { [key: string]: ButtonProps } = { - [AnnotationMode.HIGHLIGHT]: { - classname: `${CLASS_ANNOTATIONS_BUTTON} ${CLASS_HIGHLIGHT_BUTTON}`, - icon: ICON_HIGHLIGHT_TEXT, - resinTarget: 'highlightText', - testid: 'bp-AnnotationsControls-highlightBtn', - text: __('highlight_text'), - }, - [AnnotationMode.REGION]: { - classname: `${CLASS_ANNOTATIONS_BUTTON} ${CLASS_REGION_BUTTON}`, - icon: ICON_REGION_COMMENT, - resinTarget: 'highlightRegion', - testid: 'bp-AnnotationsControls-regionBtn', - text: __('region_comment'), - }, -}; - -export default class AnnotationControls { - private controls: Controls; - - private controlsElement: HTMLElement; - - private currentMode: AnnotationMode = AnnotationMode.NONE; - - private hasInit = false; - - private onEscape: () => void = noop; - - /** - * [constructor] - */ - constructor(controls: Controls) { - if (!controls || !(controls instanceof Controls)) { - throw Error('controls must be an instance of Controls'); - } - - this.controls = controls; - this.controlsElement = controls.controlsEl; - } - - /** - * [destructor] - */ - public destroy(): void { - if (!this.hasInit) { - return; - } - - document.removeEventListener('keydown', this.handleKeyDown); - - this.hasInit = false; - } - - /** - * Deactivate current control button - */ - public resetControls = (): void => { - if (this.currentMode === AnnotationMode.NONE) { - return; - } - - const prevMode = this.currentMode; - - this.currentMode = AnnotationMode.NONE; - this.updateButton(prevMode); - }; - - /** - * Show or hide the controls - */ - public toggle(show: boolean): void { - const groupElement = this.controlsElement.querySelector(`.${CLASS_ANNOTATIONS_GROUP}`); - - if (!groupElement) { - return; - } - - if (show) { - groupElement.classList.remove(CLASS_GROUP_HIDE); - } else { - groupElement.classList.add(CLASS_GROUP_HIDE); - } - } - - /** - * Update button UI - */ - private updateButton = (mode: AnnotationMode): void => { - const buttonElement = this.controlsElement.querySelector(`.${buttonClassMap[mode]}`); - - if (!buttonElement) { - return; - } - - if (this.currentMode === mode) { - buttonElement.classList.add(CLASS_BUTTON_ACTIVE); - } else { - buttonElement.classList.remove(CLASS_BUTTON_ACTIVE); - } - }; - - /** - * Set the mode. If the mode is different from what is currently saved in state, - * then reset the current controls and apply the active state based on the provided mode. - */ - public setMode(mode: AnnotationMode): void { - // Only update buttons if mode has changed - if (this.currentMode === mode) { - return; - } - - this.resetControls(); - this.currentMode = mode; - this.updateButton(mode); - } - - /** - * Escape key handler, reset all control buttons, - * and stop propagation to prevent preview modal from exiting - */ - private handleKeyDown = (event: KeyboardEvent): void => { - if (event.key !== 'Escape' || this.currentMode === AnnotationMode.NONE) { - return; - } - - this.resetControls(); - this.onEscape(); - - event.preventDefault(); - event.stopPropagation(); - }; - - private addButton = (mode: AnnotationMode, onClick: ClickHandler, parent: HTMLElement, fileId: string): void => { - const buttonProps = buttonPropsMap[mode]; - - if (!buttonProps) { - return; - } - - const buttonElement = this.controls.add( - buttonProps.text, - (event: MouseEvent) => onClick({ event, mode }), - buttonProps.classname, - buttonProps.icon, - 'button', - parent, - ); - - buttonElement.setAttribute('data-resin-target', buttonProps.resinTarget); - buttonElement.setAttribute('data-resin-fileId', fileId); - buttonElement.setAttribute('data-testid', buttonProps.testid); - }; - - /** - * Initialize the annotation controls with options. - */ - public init({ - fileId, - initialMode = AnnotationMode.NONE, - onEscape = noop, - onClick = noop, - showHighlightText = false, - }: Options): void { - if (this.hasInit) { - return; - } - const groupElement = this.controls.addGroup(CLASS_ANNOTATIONS_GROUP); - groupElement.setAttribute('data-resin-feature', 'annotations'); - - this.addButton(AnnotationMode.REGION, onClick, groupElement, fileId); - if (showHighlightText) { - this.addButton(AnnotationMode.HIGHLIGHT, onClick, groupElement, fileId); - } - - this.onEscape = onEscape; - document.addEventListener('keydown', this.handleKeyDown); - - this.hasInit = true; - - this.setMode(initialMode); - } -} diff --git a/src/lib/AnnotationControlsFSM.ts b/src/lib/AnnotationControlsFSM.ts index b9e20d2ec..142afe2ef 100644 --- a/src/lib/AnnotationControlsFSM.ts +++ b/src/lib/AnnotationControlsFSM.ts @@ -1,4 +1,6 @@ -import { AnnotationMode } from './AnnotationControls'; +import { AnnotationMode } from './types'; + +export * from './types'; export enum AnnotationState { DRAWING = 'drawing', diff --git a/src/lib/Controls.js b/src/lib/Controls.js index 7aadd4e24..853bd5f25 100644 --- a/src/lib/Controls.js +++ b/src/lib/Controls.js @@ -4,8 +4,6 @@ import { CLASS_HIDDEN } from './constants'; const SHOW_PREVIEW_CONTROLS_CLASS = 'box-show-preview-controls'; const CONTROLS_BUTTON_CLASS = 'bp-controls-btn'; -const CONTROLS_PAGE_NUM_INPUT_CLASS = 'bp-page-num-input'; -const CONTROLS_PAGE_NUM_WRAPPER_CLASS = 'bp-page-num-wrapper'; const CONTROLS_AUTO_HIDE_TIMEOUT_IN_MILLIS = 2000; export const CLASS_BOX_CONTROLS_GROUP_BUTTON = 'bp-controls-group-btn'; @@ -81,11 +79,7 @@ class Controls { * @return {boolean} true if element is a preview control button */ isPreviewControlButton(element) { - return ( - !!element && - (element.classList.contains(CONTROLS_BUTTON_CLASS) || - element.parentNode.classList.contains(CONTROLS_PAGE_NUM_WRAPPER_CLASS)) - ); + return !!element && element.classList.contains(CONTROLS_BUTTON_CLASS); } /** @@ -97,7 +91,7 @@ class Controls { this.controlDisplayTimeoutId = setTimeout(() => { clearTimeout(this.controlDisplayTimeoutId); - if (!this.shouldHide || this.isPageNumFocused()) { + if (!this.shouldHide) { this.resetTimeout(); } else { this.containerEl.classList.remove(SHOW_PREVIEW_CONTROLS_CLASS); @@ -269,16 +263,6 @@ class Controls { disable() { this.controlsEl.classList.add(CLASS_HIDDEN); } - - /** - * Determines if the page number input is focused. - * - * @public - * @return {boolean} Is the input focused - */ - isPageNumFocused() { - return document.activeElement && document.activeElement.classList.contains(CONTROLS_PAGE_NUM_INPUT_CLASS); - } } export default Controls; diff --git a/src/lib/Controls.scss b/src/lib/Controls.scss index 39d07af3f..2f2eccaf4 100644 --- a/src/lib/Controls.scss +++ b/src/lib/Controls.scss @@ -1,8 +1,5 @@ $controls-button-width: 32px; -@import './AnnotationControls'; -@import './ZoomControls'; - .bp-controls { position: absolute; bottom: 25px; @@ -14,24 +11,6 @@ $controls-button-width: 32px; opacity: 0; transition: opacity .5s; - // Page num input CSS - .bp-page-num { - width: auto; // Let page num expand as needed - min-width: 48px; - - span { - display: inline; - font-size: 14px; - } - } - - .bp-page-num-wrapper { - margin: 5px; - padding: 7px 5px; - background-color: #444; - border-radius: 3px; - } - /* stylelint-disable property-no-vendor-prefix */ // Removes the spinner for number type inputs in Webkit browsers input::-webkit-outer-spin-button, @@ -43,47 +22,7 @@ $controls-button-width: 32px; input[type='number'] { -moz-appearance: textfield; } - /* stylelint-enable property-no-vendor-prefix */ - - input[type='number'].bp-page-num-input { - position: absolute; - width: 44px; // hard-coded to solve layout issues - margin: 0 auto; - font-size: 14px; - text-align: center; - visibility: hidden; - } - - &.show-page-number-input { - .bp-page-num-wrapper { - padding: 0; - background-color: transparent; - border: none; - } - - .bp-page-num { - opacity: 1; - } - - .bp-current-page, - .bp-page-num-divider, - .bp-total-pages { - display: none; - } - - input[type='number'].bp-page-num-input { - position: static; - display: inline-block; - visibility: visible; - } - } - - .bp-zoom-btn { - display: flex; - align-items: center; - justify-content: center; - } } .box-show-preview-controls .bp-controls { diff --git a/src/lib/PageControls.js b/src/lib/PageControls.js deleted file mode 100644 index b2a9a7972..000000000 --- a/src/lib/PageControls.js +++ /dev/null @@ -1,316 +0,0 @@ -import EventEmitter from 'events'; -import fullscreen from './Fullscreen'; -import Browser from './Browser'; -import { BROWSERS } from './constants'; -import { decodeKeydown } from './util'; -import { ICON_DROP_DOWN, ICON_DROP_UP } from './icons/icons'; -import { CLASS_BOX_CONTROLS_GROUP_BUTTON } from './Controls'; - -const SHOW_PAGE_NUM_INPUT_CLASS = 'show-page-number-input'; -const CONTROLS_PAGE_NUM_WRAPPER_CLASS = 'bp-page-num-wrapper'; -const CONTROLS_CURRENT_PAGE = 'bp-current-page'; -const CONTROLS_PAGE_NUM_INPUT_CLASS = 'bp-page-num-input'; -const CONTROLS_TOTAL_PAGES = 'bp-total-pages'; -const PAGE_NUM = 'bp-page-num'; -const PREV_PAGE = 'bp-previous-page'; -const NEXT_PAGE = 'bp-next-page'; - -const pageNumTemplate = ` -
- 1 - -  /  - 1 -
`.replace(/>\s*<'); - -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 {HTMLElement} contentEl - The content element of the file - - * @return {Controls} Instance of controls - */ - constructor(controls, contentEl) { - super(); - - this.controls = controls; - this.controlsEl = controls.controlsEl; - - 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); - } - - /** - * Add the page controls - * - * @param {number} currentPageNumber - Current page number - * @param {number} pagesCount - Number of total pages - * @return {void} - */ - add(currentPageNumber, pagesCount) { - const groupElement = this.controls.addGroup(); - // const groupElement = undefined; - this.controls.add( - __('previous_page'), - this.setPreviousPage, - `${CLASS_BOX_CONTROLS_GROUP_BUTTON} bp-previous-page-icon ${PREV_PAGE}`, - ICON_DROP_UP, - undefined, - groupElement, - ); - this.controls.add( - __('enter_page_num'), - this.showPageNumInput, - PAGE_NUM, - pageNumTemplate, - undefined, - groupElement, - ); - this.controls.add( - __('next_page'), - this.setNextPage, - `${CLASS_BOX_CONTROLS_GROUP_BUTTON} bp-next-page-icon ${NEXT_PAGE}`, - ICON_DROP_DOWN, - undefined, - groupElement, - ); - - const pageNumEl = this.controlsEl.querySelector(`.${PAGE_NUM}`); - 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.checkPaginationButtons(); - } - - /** - * Replaces the page number display with an input box that allows the user to type in a page number - * - * @private - * @return {void} - */ - showPageNumInput() { - // 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.getCurrentPageNumber(); - this.pageNumInputEl.focus(); - this.pageNumInputEl.select(); - - // finish input when input is blurred or enter key is pressed - this.pageNumInputEl.addEventListener('blur', this.pageNumInputBlurHandler); - this.pageNumInputEl.addEventListener('keydown', this.pageNumInputKeydownHandler); - } - - /** - * Hide the page number input - * - * @private - * @return {void} - */ - hidePageNumInput() { - this.controlsEl.classList.remove(SHOW_PAGE_NUM_INPUT_CLASS); - this.pageNumInputEl.removeEventListener('blur', this.pageNumInputBlurHandler); - this.pageNumInputEl.removeEventListener('keydown', this.pageNumInputKeydownHandler); - } - - /** - * Disables or enables previous/next pagination buttons depending on - * current page number. - * - * @return {void} - */ - checkPaginationButtons() { - const pageNumButtonEl = this.controlsEl.querySelector(`.${PAGE_NUM}`); - const previousPageButtonEl = this.controlsEl.querySelector(`.${PREV_PAGE}`); - const nextPageButtonEl = this.controlsEl.querySelector(`.${NEXT_PAGE}`); - - // Safari disables keyboard input in fullscreen before Safari 10.1 - const isSafariFullscreen = Browser.getName() === 'Safari' && fullscreen.isFullscreen(); - - // Disable page number selector if there is only one page or less - if (pageNumButtonEl) { - if (this.getTotalPages() <= 1 || isSafariFullscreen) { - pageNumButtonEl.disabled = true; - } else { - pageNumButtonEl.disabled = false; - } - } - - // Disable previous page if on first page, otherwise enable - if (previousPageButtonEl) { - if (this.getCurrentPageNumber() === 1) { - previousPageButtonEl.disabled = true; - } else { - previousPageButtonEl.disabled = false; - } - } - - // Disable next page if on last page, otherwise enable - if (nextPageButtonEl) { - if (this.getCurrentPageNumber() === this.getTotalPages()) { - nextPageButtonEl.disabled = true; - } else { - nextPageButtonEl.disabled = false; - } - } - } - - /** - * Update page number in page control widget. - * - * @public - * @param {number} pageNumber - Number of page to update to - * @return {void} - */ - updateCurrentPage(pageNumber) { - if (this.pageNumInputEl) { - this.pageNumInputEl.value = pageNumber; - } - - if (this.currentPageEl) { - this.setCurrentPageNumber(pageNumber); - } - - 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); - } - - /** - * Blur handler for page number input. - * - * @private - * @param {Event} event Blur event - * @return {void} - */ - pageNumInputBlurHandler(event) { - const { target } = event; - const pageNumber = parseInt(target.value, 10); - - if (!Number.isNaN(pageNumber)) { - this.emit('pagechange', pageNumber); - } - - this.hidePageNumInput(); - } - - /** - * Keydown handler for page number input. - * - * @private - * @param {Event} event - Keydown event - * @return {void} - */ - pageNumInputKeydownHandler(event) { - const key = decodeKeydown(event); - - switch (key) { - case 'Enter': - case 'Tab': - this.contentEl.focus(); - // The keycode of the 'next' key on Android Chrome is 9, which maps to 'Tab'. - // 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() !== BROWSERS.INTERNET_EXPLORER) { - event.target.blur(); - } - - event.stopPropagation(); - event.preventDefault(); - break; - - case 'Escape': - this.hidePageNumInput(); - this.contentEl.focus(); - - event.stopPropagation(); - event.preventDefault(); - break; - - default: - break; - } - } -} - -export default PageControls; diff --git a/src/lib/Preview.js b/src/lib/Preview.js index f3d1867b4..e4cd47c6b 100644 --- a/src/lib/Preview.js +++ b/src/lib/Preview.js @@ -937,9 +937,6 @@ class Preview extends EventEmitter { // Enable or disable hotkeys this.options.useHotkeys = options.useHotkeys !== false; - // Enable or disable react ui - this.options.useReactControls = !!options.useReactControls; - // Custom Box3D application definition this.options.box3dApplication = options.box3dApplication; diff --git a/src/lib/ZoomControls.js b/src/lib/ZoomControls.js deleted file mode 100644 index 16c86cdc0..000000000 --- a/src/lib/ZoomControls.js +++ /dev/null @@ -1,140 +0,0 @@ -import isFinite from 'lodash/isFinite'; -import noop from 'lodash/noop'; -import { ICON_ZOOM_IN, ICON_ZOOM_OUT } from './icons/icons'; -import Controls, { CLASS_BOX_CONTROLS_GROUP_BUTTON } from './Controls'; - -const CLASS_ZOOM_CURRENT_SCALE = 'bp-ZoomControls-currentScale'; -const CLASS_ZOOM_CURRENT_SCALE_VALUE = 'bp-zoom-current-scale-value'; -const CLASS_ZOOM_IN_BUTTON = 'bp-zoom-in-btn'; -const CLASS_ZOOM_OUT_BUTTON = 'bp-zoom-out-btn'; -const CLASS_ZOOM_BUTTON = 'bp-zoom-btn'; -const ZOOM_MAX = Number.POSITIVE_INFINITY; -const ZOOM_MIN = 0.1; - -class ZoomControls { - /** @property {Controls} - Controls object */ - controls; - - /** @property {HTMLElement} - Controls element */ - controlsElement; - - /** @property {number} - Current zoom scale */ - currentScale; - - /** @property {HTMLElement} - Current scale element */ - currentScaleElement; - - /** @property {number} - Max zoom scale */ - maxZoom; - - /** @property {number} - Min zoom scale */ - minZoom; - - /** - * [constructor] - * - * @param {Controls} controls - Viewer controls - * @return {ZoomControls} Instance of ZoomControls - */ - constructor(controls) { - if (!controls || !(controls instanceof Controls)) { - throw Error('controls must be an instance of Controls'); - } - - this.controls = controls; - this.controlsElement = controls.controlsEl; - } - - /** - * Initialize the zoom controls with the initial scale and options. - * - * @param {number} currentScale - Initial scale value, assumes range on the scale of 0-1 - * @param {number} [options.maxZoom] - Maximum zoom, on the scale of 0-1, though the max could be upwards of 1 - * @param {number} [options.minZoom] - Minimum zoom, on the scale of 0-1 - * @param {String} [options.zoomInClassName] - Class name for zoom in button - * @param {String} [options.zoomOutClassName] - Class name for zoom out button - * @param {Function} [options.onZoomIn] - Callback when zoom in is triggered - * @param {Function} [options.onZoomOut] - Callback when zoom out is triggered - * @return {void} - */ - init( - currentScale, - { - zoomOutClassName = '', - zoomInClassName = '', - minZoom = ZOOM_MIN, - maxZoom = ZOOM_MAX, - onZoomIn = noop, - onZoomOut = noop, - } = {}, - ) { - this.maxZoom = Math.round((isFinite(maxZoom) && maxZoom <= ZOOM_MAX ? maxZoom : ZOOM_MAX) * 100); - this.minZoom = Math.round((isFinite(minZoom) && minZoom >= ZOOM_MIN ? minZoom : ZOOM_MIN) * 100); - - const groupElement = this.controls.addGroup(); - this.controls.add( - __('zoom_out'), - onZoomOut, - `${CLASS_BOX_CONTROLS_GROUP_BUTTON} ${CLASS_ZOOM_BUTTON} ${CLASS_ZOOM_OUT_BUTTON} ${zoomOutClassName}`, - ICON_ZOOM_OUT, - undefined, - groupElement, - ); - this.controls.add( - __('zoom_current_scale'), - undefined, - CLASS_ZOOM_CURRENT_SCALE, - `100%`, - 'div', - groupElement, - ); - this.controls.add( - __('zoom_in'), - onZoomIn, - `${CLASS_BOX_CONTROLS_GROUP_BUTTON} ${CLASS_ZOOM_BUTTON} ${CLASS_ZOOM_IN_BUTTON} ${zoomInClassName}`, - ICON_ZOOM_IN, - undefined, - groupElement, - ); - - this.currentScaleElement = this.controlsElement.querySelector(`.${CLASS_ZOOM_CURRENT_SCALE_VALUE}`); - this.setCurrentScale(currentScale); - } - - /** - * Sets the current scale - * - * @param {number} scale - New scale to be set as current, range 0-1 - * @return {void} - */ - setCurrentScale(scale) { - if (!isFinite(scale)) { - return; - } - - this.currentScale = Math.round(scale * 100); - this.currentScaleElement.textContent = `${this.currentScale}%`; - - this.checkButtonEnablement(); - } - - /** - * Checks the zoom in and zoom out button enablement - * - * @return {void} - */ - checkButtonEnablement() { - const zoomOutElement = this.controlsElement.querySelector(`.${CLASS_ZOOM_OUT_BUTTON}`); - const zoomInElement = this.controlsElement.querySelector(`.${CLASS_ZOOM_IN_BUTTON}`); - - if (zoomOutElement) { - zoomOutElement.disabled = this.currentScale <= this.minZoom; - } - - if (zoomInElement) { - zoomInElement.disabled = this.currentScale >= this.maxZoom; - } - } -} - -export default ZoomControls; diff --git a/src/lib/ZoomControls.scss b/src/lib/ZoomControls.scss deleted file mode 100644 index 9d43b41fe..000000000 --- a/src/lib/ZoomControls.scss +++ /dev/null @@ -1,6 +0,0 @@ -.bp-ZoomControls-currentScale { - min-width: 48px; - color: $white; - font-size: 14px; - text-align: center; -} diff --git a/src/lib/__tests__/AnnotationControls-test.html b/src/lib/__tests__/AnnotationControls-test.html deleted file mode 100644 index bb1d1e682..000000000 --- a/src/lib/__tests__/AnnotationControls-test.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/src/lib/__tests__/AnnotationControls-test.js b/src/lib/__tests__/AnnotationControls-test.js deleted file mode 100644 index ca02efb62..000000000 --- a/src/lib/__tests__/AnnotationControls-test.js +++ /dev/null @@ -1,257 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import { ICON_REGION_COMMENT } from '../icons/icons'; -import AnnotationControls, { - AnnotationMode, - CLASS_ANNOTATIONS_BUTTON, - CLASS_ANNOTATIONS_GROUP, - CLASS_GROUP_HIDE, - CLASS_REGION_BUTTON, -} from '../AnnotationControls'; -import Controls from '../Controls'; - -let annotationControls; -let stubs = {}; - -describe('lib/AnnotationControls', () => { - beforeEach(() => { - fixture.load('__tests__/AnnotationControls-test.html'); - stubs.classListAdd = jest.fn(); - stubs.classListRemove = jest.fn(); - stubs.onClick = jest.fn(); - stubs.querySelector = jest.fn(() => ({ - classList: { - add: stubs.classListAdd, - remove: stubs.classListRemove, - }, - })); - - const controls = new Controls(document.getElementById('test-annotation-controls-container')); - annotationControls = new AnnotationControls(controls); - annotationControls.controlsElement.querySelector = stubs.querySelector; - }); - - afterEach(() => { - fixture.cleanup(); - - annotationControls = null; - stubs = {}; - }); - - describe('constructor()', () => { - test('should create the correct DOM structure', () => { - expect(annotationControls.controls).toBeDefined(); - expect(annotationControls.controlsElement).toBeDefined(); - expect(annotationControls.currentMode).toBe(AnnotationMode.NONE); - }); - - test('should throw an exception if controls is not provided', () => { - expect(() => new AnnotationControls()).toThrowError(Error); - }); - }); - - describe('destroy()', () => { - test('should remove all listeners', () => { - jest.spyOn(document, 'removeEventListener'); - annotationControls.hasInit = true; - - annotationControls.destroy(); - - expect(document.removeEventListener).toBeCalledWith('keydown', annotationControls.handleKeyDown); - expect(annotationControls.hasInit).toBe(false); - }); - - test('should early return if hasInit is false', () => { - jest.spyOn(document, 'removeEventListener'); - - annotationControls.destroy(); - - expect(document.removeEventListener).not.toBeCalled(); - }); - }); - - describe('init()', () => { - beforeEach(() => { - jest.spyOn(annotationControls, 'addButton'); - }); - - test('should only add region button', () => { - annotationControls.init({ fileId: '0', onClick: stubs.onClick }); - - expect(annotationControls.addButton).toBeCalledWith( - AnnotationMode.REGION, - stubs.onClick, - expect.anything(), - '0', - ); - }); - - test('should add highlight button', () => { - annotationControls.init({ fileId: '0', onClick: stubs.onClick, showHighlightText: true }); - - expect(annotationControls.addButton).toBeCalledWith( - AnnotationMode.HIGHLIGHT, - stubs.onClick, - expect.anything(), - '0', - ); - }); - - test('should add keydown event listener', () => { - jest.spyOn(document, 'addEventListener'); - - annotationControls.init({ fileId: '0' }); - - expect(document.addEventListener).toBeCalledWith('keydown', annotationControls.handleKeyDown); - }); - - test('should set onEscape and hasInit', () => { - const onEscapeMock = jest.fn(); - - annotationControls.init({ fileId: '0', onEscape: onEscapeMock }); - - expect(annotationControls.onEscape).toBe(onEscapeMock); - expect(annotationControls.hasInit).toBe(true); - }); - - test('should early return if hasInit is true', () => { - annotationControls.hasInit = true; - - jest.spyOn(document, 'addEventListener'); - - annotationControls.init({ fileId: '0' }); - - expect(annotationControls.addButton).not.toBeCalled(); - expect(document.addEventListener).not.toBeCalled(); - }); - - test('should set annotationControls currentMode to be REGION', () => { - annotationControls.init({ initialMode: AnnotationMode.REGION }); - - expect(annotationControls.currentMode).toBe(AnnotationMode.REGION); - }); - }); - - describe('handleKeyDown', () => { - let eventMock; - - beforeEach(() => { - annotationControls.resetControls = jest.fn(); - annotationControls.currentMode = 'region'; - eventMock = { - key: 'Escape', - preventDefault: jest.fn(), - stopPropagation: jest.fn(), - }; - }); - - test('should not call resetControls if key is not Escape or mode is none', () => { - annotationControls.handleKeyDown({ key: 'Enter' }); - - expect(annotationControls.resetControls).not.toBeCalled(); - - annotationControls.currentMode = 'none'; - annotationControls.handleKeyDown({ key: 'Escape' }); - - expect(annotationControls.resetControls).not.toBeCalled(); - }); - - test('should call resetControls and prevent default event', () => { - annotationControls.handleKeyDown(eventMock); - - expect(eventMock.preventDefault).toBeCalled(); - expect(eventMock.stopPropagation).toBeCalled(); - }); - }); - - describe('resetControls()', () => { - beforeEach(() => { - jest.spyOn(annotationControls, 'updateButton'); - - stubs.onEscape = jest.fn(); - }); - - test('should not change if no current active control', () => { - annotationControls.resetControls(); - - expect(annotationControls.currentMode).toBe(AnnotationMode.NONE); - expect(annotationControls.updateButton).not.toBeCalled(); - }); - - test('should call updateButton if current control is region', () => { - annotationControls.currentMode = AnnotationMode.REGION; - - annotationControls.resetControls(); - - expect(annotationControls.currentMode).toBe(AnnotationMode.NONE); - expect(annotationControls.updateButton).toBeCalledWith(AnnotationMode.REGION); - }); - }); - - describe('toggle()', () => { - test('should show or hide the entire button group', () => { - annotationControls.toggle(false); - expect(stubs.querySelector).toBeCalledWith(`.${CLASS_ANNOTATIONS_GROUP}`); - expect(stubs.classListAdd).toBeCalledWith(CLASS_GROUP_HIDE); - - annotationControls.toggle(true); - expect(stubs.querySelector).toBeCalledWith(`.${CLASS_ANNOTATIONS_GROUP}`); - expect(stubs.classListRemove).toBeCalledWith(CLASS_GROUP_HIDE); - }); - }); - - describe('addButton()', () => { - beforeEach(() => { - stubs.buttonElement = { - setAttribute: jest.fn(), - }; - - jest.spyOn(annotationControls.controls, 'add').mockReturnValue(stubs.buttonElement); - }); - - test('should do nothing for unknown button', () => { - annotationControls.addButton('draw', jest.fn(), 'group', '0'); - - expect(annotationControls.controls.add).not.toBeCalled(); - }); - - test('should add controls and add resin tags', () => { - annotationControls.addButton(AnnotationMode.REGION, jest.fn(), 'group', '0'); - - expect(annotationControls.controls.add).toBeCalledWith( - __('region_comment'), - expect.any(Function), - `${CLASS_ANNOTATIONS_BUTTON} ${CLASS_REGION_BUTTON}`, - ICON_REGION_COMMENT, - 'button', - 'group', - ); - - expect(stubs.buttonElement.setAttribute).toBeCalledWith('data-resin-target', 'highlightRegion'); - expect(stubs.buttonElement.setAttribute).toBeCalledWith('data-resin-fileId', '0'); - }); - }); - - describe('setMode()', () => { - beforeEach(() => { - annotationControls.resetControls = jest.fn(); - annotationControls.updateButton = jest.fn(); - }); - - test('should do nothing if mode is the same', () => { - annotationControls.currentMode = 'region'; - annotationControls.setMode('region'); - - expect(annotationControls.resetControls).not.toBeCalled(); - expect(annotationControls.updateButton).not.toBeCalled(); - }); - - test('should update controls if mode is not the same', () => { - annotationControls.currentMode = 'region'; - - annotationControls.setMode('highlight'); - - expect(annotationControls.resetControls).toBeCalled(); - expect(annotationControls.updateButton).toBeCalledWith('highlight'); - }); - }); -}); diff --git a/src/lib/__tests__/AnnotationControlsFSM-test.js b/src/lib/__tests__/AnnotationControlsFSM-test.js index 010442abe..10b997e75 100644 --- a/src/lib/__tests__/AnnotationControlsFSM-test.js +++ b/src/lib/__tests__/AnnotationControlsFSM-test.js @@ -1,5 +1,4 @@ -import AnnotationControlsFSM, { AnnotationInput, AnnotationState } from '../AnnotationControlsFSM'; -import { AnnotationMode } from '../AnnotationControls'; +import AnnotationControlsFSM, { AnnotationInput, AnnotationMode, AnnotationState } from '../AnnotationControlsFSM'; describe('lib/AnnotationControlsFSM', () => { describe('AnnotationState.NONE', () => { diff --git a/src/lib/__tests__/Controls-test.js b/src/lib/__tests__/Controls-test.js index eebceb4ef..d6c2aeb1e 100644 --- a/src/lib/__tests__/Controls-test.js +++ b/src/lib/__tests__/Controls-test.js @@ -119,9 +119,6 @@ describe('lib/Controls', () => { element.className = ''; expect(controls.isPreviewControlButton(element)).toBe(false); - - parent.className = 'bp-page-num-wrapper'; - expect(controls.isPreviewControlButton(element)).toBe(true); }); }); @@ -153,18 +150,6 @@ describe('lib/Controls', () => { expect(resetTimeoutStub).toBeCalled(); }); - test('should call resetTimeout again if the page number input is focused', () => { - controls.shouldHide = true; - const isPageNumFocusedStub = jest.spyOn(controls, 'isPageNumFocused').mockReturnValue(true); - controls.resetTimeout(); - - const resetTimeoutStub = jest.spyOn(controls, 'resetTimeout'); - clock.tick(RESET_TIMEOUT_CLOCK_TICK); - - expect(isPageNumFocusedStub).toBeCalled(); - expect(resetTimeoutStub).toBeCalled(); - }); - test('should not remove the preview controls class if should hide is false', () => { controls.shouldHide = false; controls.containerEl.className = SHOW_PREVIEW_CONTROLS_CLASS; @@ -348,16 +333,4 @@ describe('lib/Controls', () => { expect(controls.controlsEl.classList.contains(CLASS_HIDDEN)).toBe(true); }); }); - - describe('isPageNumFocused()', () => { - test('should return true if page num element is focused', () => { - document.activeElement.classList.add('bp-page-num-input'); - expect(controls.isPageNumFocused()).toBe(true); - }); - - test('should return false if page num element is not', () => { - document.activeElement.classList.remove('bp-page-num-input'); - expect(controls.isPageNumFocused()).toBe(false); - }); - }); }); diff --git a/src/lib/__tests__/PageControls-test.html b/src/lib/__tests__/PageControls-test.html deleted file mode 100644 index 3d412d36e..000000000 --- a/src/lib/__tests__/PageControls-test.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/src/lib/__tests__/PageControls-test.js b/src/lib/__tests__/PageControls-test.js deleted file mode 100644 index c24e85ba2..000000000 --- a/src/lib/__tests__/PageControls-test.js +++ /dev/null @@ -1,289 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import PageControls from '../PageControls'; -import Controls from '../Controls'; -import fullscreen from '../Fullscreen'; -import Browser from '../Browser'; -import { BROWSERS } from '../constants'; - -let pageControls; -let stubs = {}; - -const SHOW_PAGE_NUM_INPUT_CLASS = 'show-page-number-input'; -const PAGE_NUM = 'bp-page-num'; -const PREV_PAGE = 'bp-previous-page'; -const NEXT_PAGE = 'bp-next-page'; - -describe('lib/PageControls', () => { - beforeEach(() => { - fixture.load('__tests__/PageControls-test.html'); - const controls = new Controls(document.getElementById('test-page-controls-container')); - pageControls = new PageControls(controls, jest.fn(), jest.fn()); - }); - - afterEach(() => { - fixture.cleanup(); - - if (pageControls && typeof pageControls.destroy === 'function') { - pageControls.destroy(); - } - - pageControls = null; - stubs = {}; - }); - - describe('constructor()', () => { - test('should create the correct DOM structure', () => { - expect(pageControls.controlsEl).toBeDefined(); - }); - }); - - describe('add()', () => { - beforeEach(() => { - stubs.currentPageNumber = 1; - stubs.pagesCount = 10; - stubs.add = jest.spyOn(pageControls.controls, 'add'); - stubs.checkPaginationButtons = jest.spyOn(pageControls, 'checkPaginationButtons'); - }); - - test('should add the page number controls', () => { - pageControls.add(stubs.currentPageNumber, stubs.pagesCount); - - expect(stubs.add).toBeCalledTimes(3); - }); - - test('should initialize the number of total pages', () => { - pageControls.add(stubs.currentPageNumber, stubs.pagesCount); - - expect(pageControls.controls.buttonRefs.length).toBe(3); - expect(parseInt(pageControls.totalPagesEl.textContent, 10)).toBe(stubs.pagesCount); - }); - - test('should initialize the current page number', () => { - pageControls.add(stubs.currentPageNumber, stubs.pagesCount); - - expect(parseInt(pageControls.currentPageEl.textContent, 10)).toBe(stubs.currentPageNumber); - }); - - test('should check the pagination buttons', () => { - pageControls.add(stubs.currentPageNumber, stubs.pagesCount); - expect(stubs.checkPaginationButtons).toBeCalled(); - }); - }); - - describe('showPageNumInput()', () => { - test('should set the page number input value, focus, select, and add listeners', () => { - pageControls.currentPageEl = 0; - pageControls.pageNumInputEl = { - value: 0, - focus: jest.fn(), - select: jest.fn(), - addEventListener: jest.fn(), - }; - - pageControls.showPageNumInput(); - expect(pageControls.controlsEl).toHaveClass(SHOW_PAGE_NUM_INPUT_CLASS); - expect(pageControls.pageNumInputEl.focus).toBeCalled(); - expect(pageControls.pageNumInputEl.select).toBeCalled(); - expect(pageControls.pageNumInputEl.addEventListener).toBeCalledWith('blur', expect.any(Function)); - expect(pageControls.pageNumInputEl.addEventListener).toBeCalledWith('keydown', expect.any(Function)); - }); - }); - - describe('hidePageNumInput()', () => { - test('should hide the input class and remove event listeners', () => { - pageControls.pageNumInputEl = { - removeEventListener: jest.fn(), - }; - - pageControls.hidePageNumInput(); - expect(pageControls.controlsEl).not.toHaveClass(SHOW_PAGE_NUM_INPUT_CLASS); - expect(pageControls.pageNumInputEl.removeEventListener).toBeCalledWith('blur', expect.any(Function)); - expect(pageControls.pageNumInputEl.removeEventListener).toBeCalledWith('keydown', expect.any(Function)); - }); - }); - - describe('checkPaginationButtons()', () => { - beforeEach(() => { - pageControls.add(1, 10); - stubs.pageNumButtonEl = pageControls.controlsEl.querySelector(`.${PAGE_NUM}`); - stubs.previousPageButtonEl = pageControls.controlsEl.querySelector(`.${PREV_PAGE}`); - stubs.nextPageButtonEl = pageControls.controlsEl.querySelector(`.${NEXT_PAGE}`); - - stubs.browser = jest.spyOn(Browser, 'getName').mockReturnValue('Safari'); - stubs.fullscreen = jest.spyOn(fullscreen, 'isFullscreen').mockReturnValue(true); - }); - - test('should disable/enable page number button el based on current page and browser type', () => { - pageControls.checkPaginationButtons(); - expect(stubs.pageNumButtonEl.disabled).toBe(true); - - stubs.browser.mockReturnValue('Chrome'); - pageControls.checkPaginationButtons(); - expect(stubs.pageNumButtonEl.disabled).toBe(false); - - stubs.browser.mockReturnValue('Safari'); - stubs.fullscreen.mockReturnValue(false); - pageControls.checkPaginationButtons(); - expect(stubs.pageNumButtonEl.disabled).toBe(false); - - pageControls.totalPagesEl.textContent = '1'; - pageControls.checkPaginationButtons(); - expect(stubs.pageNumButtonEl.disabled).toBe(true); - }); - - test('should disable/enable previous page button el based on current page', () => { - pageControls.checkPaginationButtons(); - expect(stubs.previousPageButtonEl.disabled).toBe(true); - - pageControls.setCurrentPageNumber(3); - pageControls.checkPaginationButtons(); - expect(stubs.previousPageButtonEl.disabled).toBe(false); - }); - - test('should disable/enable next page button el based on current page', () => { - pageControls.checkPaginationButtons(); - expect(stubs.nextPageButtonEl.disabled).toBe(false); - - pageControls.setCurrentPageNumber(10); - pageControls.checkPaginationButtons(); - expect(stubs.nextPageButtonEl.disabled).toBe(true); - }); - }); - - describe('updateCurrentPage()', () => { - test('should update the page to a value', () => { - pageControls.pagesCount = 10; - pageControls.pageNumInputEl = { - value: 1, - textContent: 1, - }; - const checkPaginationButtonsStub = jest.spyOn(pageControls, 'checkPaginationButtons'); - - pageControls.updateCurrentPage(7); - expect(checkPaginationButtonsStub).toBeCalled(); - expect(pageControls.pageNumInputEl.value).toBe(7); - }); - }); - - describe('setPreviousPage()', () => { - test('should emit the page change event for the previous page', () => { - stubs.emit = jest.spyOn(pageControls, 'emit'); - stubs.getCurrentPageNumber = jest.spyOn(pageControls, 'getCurrentPageNumber').mockReturnValue(3); - - pageControls.setPreviousPage(); - expect(stubs.emit).toBeCalledWith('pagechange', 2); - }); - }); - - describe('setNextPage()', () => { - test('should emit the page change event for the next page', () => { - stubs.emit = jest.spyOn(pageControls, 'emit'); - stubs.getCurrentPageNumber = jest.spyOn(pageControls, 'getCurrentPageNumber').mockReturnValue(3); - - pageControls.setNextPage(); - expect(stubs.emit).toBeCalledWith('pagechange', 4); - }); - }); - - describe('currentPageNumber', () => { - beforeEach(() => { - pageControls.currentPageEl = { - textContent: '1', - }; - }); - - describe('getCurrentPageNumber()', () => { - test('should return the correct page number', () => { - const currPageNum = pageControls.getCurrentPageNumber(); - expect(currPageNum).toBe(1); - }); - }); - - describe('setCurrentPageNumber()', () => { - test('should set the correct value', () => { - pageControls.setCurrentPageNumber(3); - const currPageNum = pageControls.getCurrentPageNumber(); - expect(currPageNum).toBe(3); - }); - }); - }); - - describe('getTotalPages()', () => { - test('should return the total number of pages', () => { - pageControls.add(1, 10); - expect(pageControls.getTotalPages()).toBe(10); - }); - }); - - describe('pageNumInputBlurHandler()', () => { - beforeEach(() => { - stubs.event = { - target: { - value: 5, - }, - }; - stubs.emit = jest.spyOn(pageControls, 'emit'); - stubs.hidePageNumInputStub = jest.spyOn(pageControls, 'hidePageNumInput').mockImplementation(); - }); - - test('should hide the page number input and set the page if given valid input', () => { - pageControls.pageNumInputBlurHandler(stubs.event); - expect(stubs.emit).toBeCalledWith('pagechange', stubs.event.target.value); - expect(stubs.hidePageNumInputStub).toBeCalled(); - }); - - test('should hide the page number input but not set the page if given invalid input', () => { - stubs.event.target.value = 'not a number'; - - pageControls.pageNumInputBlurHandler(stubs.event); - expect(stubs.emit).not.toBeCalled(); - expect(stubs.hidePageNumInputStub).toBeCalled(); - }); - }); - - describe('pageNumInputKeydownHandler()', () => { - beforeEach(() => { - stubs.event = { - key: 'Enter', - stopPropagation: jest.fn(), - preventDefault: jest.fn(), - target: { - blur: jest.fn(), - }, - }; - pageControls.contentEl = { - focus: jest.fn(), - }; - stubs.browser = jest.spyOn(Browser, 'getName').mockReturnValue(BROWSERS.INTERNET_EXPLORER); - stubs.hidePageNumInput = jest.spyOn(pageControls, 'hidePageNumInput').mockImplementation(); - }); - - test("should focus the doc element and stop default actions on 'enter'", () => { - pageControls.pageNumInputKeydownHandler(stubs.event); - expect(stubs.browser).toBeCalled(); - expect(pageControls.contentEl.focus).toBeCalled(); - expect(stubs.event.stopPropagation).toBeCalled(); - expect(stubs.event.preventDefault).toBeCalled(); - }); - - test("should blur if not IE and stop default actions on 'enter'", () => { - stubs.browser.mockReturnValue('Chrome'); - - pageControls.pageNumInputKeydownHandler(stubs.event); - expect(stubs.browser).toBeCalled(); - expect(stubs.event.target.blur).toBeCalled(); - expect(stubs.event.stopPropagation).toBeCalled(); - expect(stubs.event.preventDefault).toBeCalled(); - }); - - test("should hide the page number input, focus the document, and stop default actions on 'Esc'", () => { - stubs.event.key = 'Esc'; - - pageControls.pageNumInputKeydownHandler(stubs.event); - expect(stubs.hidePageNumInput).toBeCalled(); - expect(pageControls.contentEl.focus).toBeCalled(); - expect(stubs.event.stopPropagation).toBeCalled(); - expect(stubs.event.preventDefault).toBeCalled(); - }); - }); -}); diff --git a/src/lib/__tests__/Preview-test.js b/src/lib/__tests__/Preview-test.js index 7ff986348..1f4dc08c0 100644 --- a/src/lib/__tests__/Preview-test.js +++ b/src/lib/__tests__/Preview-test.js @@ -1377,19 +1377,6 @@ describe('lib/Preview', () => { expect(preview.options.responseInterceptor).toBe(responseInterceptor); }); - - test('should disable react controls by default', () => { - preview.parseOptions(preview.previewOptions); - - expect(preview.options.useReactControls).toBe(false); - }); - - test('should enable react controls if provided', () => { - preview.previewOptions.useReactControls = true; - preview.parseOptions(preview.previewOptions); - - expect(preview.options.useReactControls).toBe(true); - }); }); describe('createViewerOptions()', () => { diff --git a/src/lib/__tests__/ZoomControls-test.html b/src/lib/__tests__/ZoomControls-test.html deleted file mode 100644 index e68e7ca1e..000000000 --- a/src/lib/__tests__/ZoomControls-test.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/src/lib/__tests__/ZoomControls-test.js b/src/lib/__tests__/ZoomControls-test.js deleted file mode 100644 index 634a1322b..000000000 --- a/src/lib/__tests__/ZoomControls-test.js +++ /dev/null @@ -1,194 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import ZoomControls from '../ZoomControls'; -import Controls from '../Controls'; -import { ICON_ZOOM_OUT, ICON_ZOOM_IN } from '../icons/icons'; - -let zoomControls; -let stubs = {}; - -describe('lib/ZoomControls', () => { - beforeEach(() => { - fixture.load('__tests__/ZoomControls-test.html'); - const controls = new Controls(document.getElementById('test-zoom-controls-container')); - zoomControls = new ZoomControls(controls); - }); - - afterEach(() => { - fixture.cleanup(); - - zoomControls = null; - stubs = {}; - }); - - describe('constructor()', () => { - test('should create the correct DOM structure', () => { - expect(zoomControls.controlsElement).toBeDefined(); - }); - - test('should throw an exception if controls is not provided', () => { - expect(() => new ZoomControls()).toThrowError(Error); - }); - }); - - describe('init()', () => { - beforeEach(() => { - stubs.add = jest.spyOn(zoomControls.controls, 'add'); - stubs.setCurrentScale = jest.spyOn(zoomControls, 'setCurrentScale'); - stubs.onZoomIn = jest.fn(); - stubs.onZoomOut = jest.fn(); - }); - - test('should add the controls', () => { - zoomControls.init(0.5, { onZoomIn: stubs.onZoomIn, onZoomOut: stubs.onZoomOut }); - - expect(stubs.add).toBeCalledWith( - __('zoom_out'), - stubs.onZoomOut, - 'bp-controls-group-btn bp-zoom-btn bp-zoom-out-btn ', - ICON_ZOOM_OUT, - undefined, - expect.anything(), - ); - expect(stubs.add).toBeCalledWith( - __('zoom_current_scale'), - undefined, - 'bp-ZoomControls-currentScale', - expect.any(String), - 'div', - expect.anything(), - ); - expect(stubs.add).toBeCalledWith( - __('zoom_in'), - stubs.onZoomIn, - 'bp-controls-group-btn bp-zoom-btn bp-zoom-in-btn ', - ICON_ZOOM_IN, - undefined, - expect.anything(), - ); - expect(zoomControls.currentScaleElement).toBeDefined(); - expect(stubs.setCurrentScale).toBeCalledWith(0.5); - expect(zoomControls.maxZoom).toBe(Number.POSITIVE_INFINITY); - expect(zoomControls.minZoom).toBe(10); - }); - - test('should set the min and max zooms if specified', () => { - zoomControls.init(0.5, { minZoom: 0.5, maxZoom: 5 }); - - expect(zoomControls.maxZoom).toBe(500); - expect(zoomControls.minZoom).toBe(50); - }); - - test('should set the min zoom to 0 if negative is provided', () => { - zoomControls.init(0.5, { minZoom: -0.2, maxZoom: 5 }); - - expect(zoomControls.maxZoom).toBe(500); - expect(zoomControls.minZoom).toBe(10); - }); - - test('should set the min zoom to 0.1 if number is not provided', () => { - zoomControls.init(0.5, { minZoom: '0.2', maxZoom: 5 }); - - expect(zoomControls.maxZoom).toBe(500); - expect(zoomControls.minZoom).toBe(10); - }); - - test('should set the max zoom to Number.POSITIVE_INFINITY if number is not provided', () => { - zoomControls.init(0.5, { minZoom: 0.5, maxZoom: '100' }); - - expect(zoomControls.maxZoom).toBe(Number.POSITIVE_INFINITY); - expect(zoomControls.minZoom).toBe(50); - }); - - test('should set optional classnames if specified', () => { - zoomControls.init(0.5, { - zoomInClassName: 'zoom-in-classname', - zoomOutClassName: 'zoom-out-classname', - onZoomIn: stubs.onZoomIn, - onZoomOut: stubs.onZoomOut, - }); - - expect(stubs.add).toBeCalledWith( - __('zoom_out'), - stubs.onZoomOut, - 'bp-controls-group-btn bp-zoom-btn bp-zoom-out-btn zoom-out-classname', - ICON_ZOOM_OUT, - undefined, - expect.anything(), - ); - expect(stubs.add).toBeCalledWith( - __('zoom_current_scale'), - undefined, - 'bp-ZoomControls-currentScale', - expect.any(String), - 'div', - expect.anything(), - ); - expect(stubs.add).toBeCalledWith( - __('zoom_in'), - stubs.onZoomIn, - 'bp-controls-group-btn bp-zoom-btn bp-zoom-in-btn zoom-in-classname', - ICON_ZOOM_IN, - undefined, - expect.anything(), - ); - }); - }); - - describe('setCurrentScale()', () => { - beforeEach(() => { - stubs.checkButtonEnablement = jest.spyOn(zoomControls, 'checkButtonEnablement'); - zoomControls.currentScaleElement = document.createElement('span'); - zoomControls.currentScaleElement.textContent = '100%'; - }); - - test('should not do anything if scale is not provided', () => { - zoomControls.setCurrentScale(); - - expect(zoomControls.currentScale).toBeUndefined(); - expect(zoomControls.currentScaleElement.textContent).toBe('100%'); - expect(stubs.checkButtonEnablement).not.toBeCalled(); - }); - - test('should not do anything if scale is not a number', () => { - zoomControls.setCurrentScale('100'); - - expect(zoomControls.currentScale).toBeUndefined(); - expect(zoomControls.currentScaleElement.textContent).toBe('100%'); - expect(stubs.checkButtonEnablement).not.toBeCalled(); - }); - - test('should set the scale and update the text', () => { - zoomControls.setCurrentScale(0.5); - - expect(zoomControls.currentScale).toBe(50); - expect(zoomControls.currentScaleElement.textContent).toBe('50%'); - expect(stubs.checkButtonEnablement).toBeCalled(); - }); - }); - - describe('checkButtonEnablement()', () => { - test('should do nothing if currentScale is not at the limits', () => { - zoomControls.init(0.5, { maxZoom: 5, minZoom: 0.3 }); - zoomControls.checkButtonEnablement(); - - expect(zoomControls.controlsElement.querySelector('.bp-zoom-out-btn').disabled).toBe(false); - expect(zoomControls.controlsElement.querySelector('.bp-zoom-in-btn').disabled).toBe(false); - }); - - test('should disable zoom out if currentScale is at the minZoom limit', () => { - zoomControls.init(0.3, { maxZoom: 5, minZoom: 0.3 }); - zoomControls.checkButtonEnablement(); - - expect(zoomControls.controlsElement.querySelector('.bp-zoom-out-btn').disabled).toBe(true); - expect(zoomControls.controlsElement.querySelector('.bp-zoom-in-btn').disabled).toBe(false); - }); - - test('should disable zoom in if currentScale is at the maxZoom limit', () => { - zoomControls.init(5, { maxZoom: 5, minZoom: 0.3 }); - zoomControls.checkButtonEnablement(); - - expect(zoomControls.controlsElement.querySelector('.bp-zoom-out-btn').disabled).toBe(false); - expect(zoomControls.controlsElement.querySelector('.bp-zoom-in-btn').disabled).toBe(true); - }); - }); -}); diff --git a/src/lib/icons/arrow_drop_down_24px.svg b/src/lib/icons/arrow_drop_down_24px.svg deleted file mode 100755 index e940de883..000000000 --- a/src/lib/icons/arrow_drop_down_24px.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/lib/icons/arrow_drop_up_24px.svg b/src/lib/icons/arrow_drop_up_24px.svg deleted file mode 100755 index f75287184..000000000 --- a/src/lib/icons/arrow_drop_up_24px.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/lib/icons/delete_24px.svg b/src/lib/icons/delete_24px.svg deleted file mode 100755 index 540623ca3..000000000 --- a/src/lib/icons/delete_24px.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/lib/icons/highlight_text.svg b/src/lib/icons/highlight_text.svg deleted file mode 100644 index 374978b20..000000000 --- a/src/lib/icons/highlight_text.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/lib/icons/icons.js b/src/lib/icons/icons.js index a2d731b30..d468c3e52 100644 --- a/src/lib/icons/icons.js +++ b/src/lib/icons/icons.js @@ -1,13 +1,5 @@ -import DROP_DOWN from './arrow_drop_down_24px.svg'; -import DROP_UP from './arrow_drop_up_24px.svg'; -import DELETE from './delete_24px.svg'; import FULLSCREEN_IN from './full_screen_in_24px.svg'; import FULLSCREEN_OUT from './full_screen_out_24px.svg'; -import ROTATE_LEFT from './rotate_left_24px.svg'; -import ZOOM_IN from './zoom_in.svg'; -import ZOOM_OUT from './zoom_out.svg'; -import HIGHLIGHT_TEXT from './highlight_text.svg'; -import REGION_COMMENT from './region_comment.svg'; import ARROW_LEFT from './arrow_left_24px.svg'; import ARROW_RIGHT from './arrow_right_24px.svg'; import CHECK_MARK from './checkmark_24px.svg'; @@ -47,18 +39,9 @@ import FIND_DROP_UP from './arrow_drop_up.svg'; import CLOSE from './close.svg'; import SEARCH from './search.svg'; import PRINT_CHECKMARK from './print_checkmark.svg'; -import THUMBNAILS_TOGGLE from './thumbnails-toggle-icon.svg'; -export const ICON_DROP_DOWN = DROP_DOWN; -export const ICON_DROP_UP = DROP_UP; -export const ICON_DELETE = DELETE; export const ICON_FULLSCREEN_IN = FULLSCREEN_IN; export const ICON_FULLSCREEN_OUT = FULLSCREEN_OUT; -export const ICON_ROTATE_LEFT = ROTATE_LEFT; -export const ICON_ZOOM_IN = ZOOM_IN; -export const ICON_ZOOM_OUT = ZOOM_OUT; -export const ICON_HIGHLIGHT_TEXT = HIGHLIGHT_TEXT; -export const ICON_REGION_COMMENT = REGION_COMMENT; export const ICON_ARROW_LEFT = ARROW_LEFT; export const ICON_ARROW_RIGHT = ARROW_RIGHT; export const ICON_CHECK_MARK = CHECK_MARK; @@ -74,7 +57,6 @@ export const ICON_FIND_DROP_UP = FIND_DROP_UP; export const ICON_CLOSE = CLOSE; export const ICON_SEARCH = SEARCH; export const ICON_PRINT_CHECKMARK = PRINT_CHECKMARK; -export const ICON_THUMBNAILS_TOGGLE = THUMBNAILS_TOGGLE; const FILE_LOADING_ICONS = { FILE_AUDIO, diff --git a/src/lib/icons/region_comment.svg b/src/lib/icons/region_comment.svg deleted file mode 100644 index 4027ddb2d..000000000 --- a/src/lib/icons/region_comment.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/lib/icons/rotate_left_24px.svg b/src/lib/icons/rotate_left_24px.svg deleted file mode 100755 index 43ff639e8..000000000 --- a/src/lib/icons/rotate_left_24px.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/lib/icons/zoom_in.svg b/src/lib/icons/zoom_in.svg deleted file mode 100644 index 7df7b9033..000000000 --- a/src/lib/icons/zoom_in.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/lib/icons/zoom_out.svg b/src/lib/icons/zoom_out.svg deleted file mode 100644 index efdafb381..000000000 --- a/src/lib/icons/zoom_out.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/lib/viewers/controls/annotations/types.ts b/src/lib/types/annotations.ts similarity index 100% rename from src/lib/viewers/controls/annotations/types.ts rename to src/lib/types/annotations.ts diff --git a/src/lib/types/index.ts b/src/lib/types/index.ts new file mode 100644 index 000000000..6e3360112 --- /dev/null +++ b/src/lib/types/index.ts @@ -0,0 +1 @@ +export * from './annotations'; diff --git a/src/lib/viewers/BaseViewer.js b/src/lib/viewers/BaseViewer.js index bf9881a94..f6bef1253 100644 --- a/src/lib/viewers/BaseViewer.js +++ b/src/lib/viewers/BaseViewer.js @@ -38,8 +38,7 @@ import { import { EXCLUDED_EXTENSIONS } from '../extensions'; import { getIconFromExtension, getIconFromName } from '../icons/icons'; import { VIEWER_EVENT, ERROR_CODE, LOAD_METRIC, DOWNLOAD_REACHABILITY_METRICS } from '../events'; -import { AnnotationMode } from '../AnnotationControls'; -import AnnotationControlsFSM, { AnnotationInput } from '../AnnotationControlsFSM'; +import AnnotationControlsFSM, { AnnotationInput, AnnotationMode } from '../AnnotationControlsFSM'; import AnnotationModule from '../AnnotationModule'; import PreviewError from '../PreviewError'; import Timer from '../Timer'; diff --git a/src/lib/viewers/__tests__/BaseViewer-test.js b/src/lib/viewers/__tests__/BaseViewer-test.js index 22b7797b9..37e9cebb3 100644 --- a/src/lib/viewers/__tests__/BaseViewer-test.js +++ b/src/lib/viewers/__tests__/BaseViewer-test.js @@ -11,7 +11,7 @@ import intl from '../../i18n'; import PreviewError from '../../PreviewError'; import RepStatus from '../../RepStatus'; import Timer from '../../Timer'; -import { AnnotationMode } from '../../AnnotationControls'; +import { AnnotationMode } from '../../types'; import { ERROR_CODE, LOAD_METRIC, VIEWER_EVENT } from '../../events'; import { EXCLUDED_EXTENSIONS } from '../../extensions'; diff --git a/src/lib/viewers/controls/annotations/AnnotationsButton.tsx b/src/lib/viewers/controls/annotations/AnnotationsButton.tsx index 67262924f..9b9b2568e 100644 --- a/src/lib/viewers/controls/annotations/AnnotationsButton.tsx +++ b/src/lib/viewers/controls/annotations/AnnotationsButton.tsx @@ -1,7 +1,7 @@ import React from 'react'; import classNames from 'classnames'; import noop from 'lodash/noop'; -import { AnnotationMode } from './types'; +import { AnnotationMode } from '../../../types'; import './AnnotationsButton.scss'; export type Props = Omit, 'onClick'> & { diff --git a/src/lib/viewers/controls/annotations/AnnotationsControls.tsx b/src/lib/viewers/controls/annotations/AnnotationsControls.tsx index bddd1ca2e..cae5e401b 100644 --- a/src/lib/viewers/controls/annotations/AnnotationsControls.tsx +++ b/src/lib/viewers/controls/annotations/AnnotationsControls.tsx @@ -6,7 +6,7 @@ import IconDrawing24 from '../icons/IconDrawing24'; import IconHighlightText16 from '../icons/IconHighlightText16'; import IconRegion24 from '../icons/IconRegion24'; import useFullscreen from '../hooks/useFullscreen'; -import { AnnotationMode } from './types'; +import { AnnotationMode } from '../../../types'; import './AnnotationsControls.scss'; export type Props = { diff --git a/src/lib/viewers/controls/annotations/DrawingControls.tsx b/src/lib/viewers/controls/annotations/DrawingControls.tsx index f168bd1ab..d9af77e64 100644 --- a/src/lib/viewers/controls/annotations/DrawingControls.tsx +++ b/src/lib/viewers/controls/annotations/DrawingControls.tsx @@ -1,7 +1,7 @@ import React from 'react'; import ColorPickerControl from '../color-picker'; import { ANNOTATION_COLORS } from '../../../AnnotationModule'; -import { AnnotationMode } from './types'; +import { AnnotationMode } from '../../../types'; export type Props = { annotationColor?: string; diff --git a/src/lib/viewers/controls/annotations/__tests__/AnnotationsButton-test.tsx b/src/lib/viewers/controls/annotations/__tests__/AnnotationsButton-test.tsx index 8162253be..f42edda4e 100644 --- a/src/lib/viewers/controls/annotations/__tests__/AnnotationsButton-test.tsx +++ b/src/lib/viewers/controls/annotations/__tests__/AnnotationsButton-test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; import AnnotationsButton from '../AnnotationsButton'; -import { AnnotationMode } from '../types'; +import { AnnotationMode } from '../../../../types'; describe('AnnotationsButton', () => { const getWrapper = (props = {}): ShallowWrapper => diff --git a/src/lib/viewers/controls/annotations/__tests__/AnnotationsControls-test.tsx b/src/lib/viewers/controls/annotations/__tests__/AnnotationsControls-test.tsx index bd810e71a..44d030ffc 100644 --- a/src/lib/viewers/controls/annotations/__tests__/AnnotationsControls-test.tsx +++ b/src/lib/viewers/controls/annotations/__tests__/AnnotationsControls-test.tsx @@ -3,7 +3,7 @@ import { act } from 'react-dom/test-utils'; import { bdlBoxBlue } from 'box-ui-elements/es/styles/variables'; import { ReactWrapper, mount } from 'enzyme'; import AnnotationsControls from '../AnnotationsControls'; -import { AnnotationMode } from '../types'; +import { AnnotationMode } from '../../../../types'; describe('AnnotationsControls', () => { const getWrapper = (props = {}): ReactWrapper => mount(); diff --git a/src/lib/viewers/controls/annotations/__tests__/DrawingControls-test.tsx b/src/lib/viewers/controls/annotations/__tests__/DrawingControls-test.tsx index e1032421b..359eb55e6 100644 --- a/src/lib/viewers/controls/annotations/__tests__/DrawingControls-test.tsx +++ b/src/lib/viewers/controls/annotations/__tests__/DrawingControls-test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { shallow, ShallowWrapper } from 'enzyme'; import DrawingControls from '../DrawingControls'; -import { AnnotationMode } from '../types'; +import { AnnotationMode } from '../../../../types'; describe('DrawingControls', () => { const getWrapper = (props = {}): ShallowWrapper => diff --git a/src/lib/viewers/controls/zoom/ZoomControls.tsx b/src/lib/viewers/controls/zoom/ZoomControls.tsx index fd2e2ddd2..707209409 100644 --- a/src/lib/viewers/controls/zoom/ZoomControls.tsx +++ b/src/lib/viewers/controls/zoom/ZoomControls.tsx @@ -40,7 +40,7 @@ export default function ZoomControls({
{`${Math.round(currentScale * 100)}%`}