Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(loading): Add options for loading icon and progress bar #1344

Merged
merged 2 commits into from
Mar 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/lib/Preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,12 @@ class Preview extends EventEmitter {
// Whether annotations v2 should be shown
this.options.showAnnotations = !!options.showAnnotations;

// Whether the loading indicator should be shown
this.options.showLoading = options.showLoading !== false;

// Whether the progress indicator should be shown
this.options.showProgress = options.showProgress !== false;

// Whether annotations v4 buttons should be shown in toolbar
this.options.showAnnotationsControls = !!options.showAnnotationsControls;

Expand Down
76 changes: 69 additions & 7 deletions src/lib/PreviewUI.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import ProgressBar from './ProgressBar';
import shellTemplate from './shell.html';
import Notification from './Notification';
import { insertTemplate } from './util';
import {
CLASS_BOX_PREVIEW_BASE_HEADER,
CLASS_BOX_PREVIEW_HAS_HEADER,
Expand All @@ -25,7 +24,10 @@ import {
SELECTOR_NAVIGATION_LEFT,
SELECTOR_NAVIGATION_RIGHT,
SELECTOR_BOX_PREVIEW_CONTENT,
SELECTOR_BOX_PREVIEW_ICON,
} from './constants';
import { getIconFromName, getIconFromExtension } from './icons/icons';
import { insertTemplate } from './util';

class PreviewUI {
/** @property {HTMLElement} - Container element */
Expand Down Expand Up @@ -122,10 +124,16 @@ class PreviewUI {
}

// Setup progress bar
this.progressBar = new ProgressBar(this.container);
if (options.showProgress) {
this.progressBar = new ProgressBar(this.container);
}

// Setup loading indicator
this.setupLoading();
if (options.showLoading) {
this.setupLoading();
} else {
this.destroyLoading();
}

// Attach keyboard events
document.addEventListener('keydown', this.keydownHandler);
Expand Down Expand Up @@ -258,7 +266,7 @@ class PreviewUI {
}

/**
* Shows the loading indicator
* Shows the loading indicator.
*
* @public
* @return {void}
Expand All @@ -281,22 +289,59 @@ class PreviewUI {
}

this.previewContainer.classList.add(CLASS_PREVIEW_LOADED);
this.showCrawler();
}

/**
* Hides the loading crawler.
*
* @public
* @return {void}
*/
hideCrawler() {
const crawler = this.previewContainer.querySelector(SELECTOR_BOX_PREVIEW_CRAWLER_WRAPPER);
if (crawler) {
crawler.classList.add(CLASS_HIDDEN);
}
}

// Re-show the cralwer for the next preview since it is hidden in finishLoadingSetup() in BaseViewer.js
/**
* Shows the loading crawler.
*
* @public
* @return {void}
*/
showCrawler() {
const crawler = this.previewContainer.querySelector(SELECTOR_BOX_PREVIEW_CRAWLER_WRAPPER);
if (crawler) {
crawler.classList.remove(CLASS_HIDDEN);
}
}

/**
* Set the icon for the loading indicator based on the file extension.
*
* @public
* @param {string} extension - File extension
* @return {void}
*/
setLoadingIcon(extension) {
const iconWrapperEl = this.container.querySelector(SELECTOR_BOX_PREVIEW_ICON);
if (iconWrapperEl) {
iconWrapperEl.innerHTML = getIconFromExtension(extension) || getIconFromName('FILE_DEFAULT');
}
}

/**
* Shows and starts a progress bar at the top of the preview.
*
* @public
* @return {void}
*/
startProgressBar() {
this.progressBar.start();
if (this.progressBar) {
this.progressBar.start();
}
}

/**
Expand All @@ -306,7 +351,9 @@ class PreviewUI {
* @return {void}
*/
finishProgressBar() {
this.progressBar.finish();
if (this.progressBar) {
this.progressBar.finish();
}
}

/**
Expand Down Expand Up @@ -376,6 +423,21 @@ class PreviewUI {
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* Remove global loading indicators from the shell
*
* @private
* @return {void}
*/
destroyLoading() {
const loadingWrapperEl = this.container.querySelector(SELECTOR_BOX_PREVIEW_LOADING_WRAPPER);
if (!loadingWrapperEl) {
return;
}

loadingWrapperEl.parentElement.removeChild(loadingWrapperEl);
}

/**
* Sets up the preview header.
*
Expand Down
18 changes: 18 additions & 0 deletions src/lib/__tests__/Preview-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1310,6 +1310,24 @@ describe('lib/Preview', () => {
expect(preview.options.showAnnotations).toBe(true);
});

test('should set whether to show loading indicators', () => {
preview.parseOptions(preview.previewOptions);
expect(preview.options.showLoading).toBe(true);

preview.previewOptions.showLoading = false;
preview.parseOptions(preview.previewOptions);
expect(preview.options.showLoading).toBe(false);
});

test('should set whether to show progress indicators', () => {
preview.parseOptions(preview.previewOptions);
expect(preview.options.showProgress).toBe(true);

preview.previewOptions.showProgress = false;
preview.parseOptions(preview.previewOptions);
expect(preview.options.showProgress).toBe(false);
});

test('should set whether to skip load from the server and any server updates', () => {
preview.parseOptions(preview.previewOptions);
expect(preview.options.skipServerUpdate).toBe(false);
Expand Down
47 changes: 46 additions & 1 deletion src/lib/__tests__/PreviewUI-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-unused-expressions */
import * as constants from '../constants';
import PreviewUI from '../PreviewUI';
import { getIconFromExtension } from '../icons/icons';

const sandbox = sinon.createSandbox();
let ui;
Expand All @@ -19,6 +20,8 @@ describe('lib/PreviewUI', () => {
containerEl = document.querySelector('.ui');
options = {
container: containerEl,
showLoading: true,
showProgress: true,
};
});

Expand Down Expand Up @@ -64,6 +67,17 @@ describe('lib/PreviewUI', () => {
expect(loadingWrapperEl).toContainHTML('Download File');
});

test('should not setup the progress bar or loading state if their respective option is false', () => {
const resultEl = ui.setup({ container: containerEl, showLoading: false, showProgress: false });
expect(resultEl).not.toContainSelector(constants.SELECTOR_BOX_PREVIEW_PROGRESS_BAR);

// Check loading state
expect(resultEl).not.toContainSelector(constants.SELECTOR_BOX_PREVIEW_LOADING_WRAPPER);
expect(resultEl).not.toContainSelector(constants.SELECTOR_BOX_PREVIEW_ICON);
expect(resultEl).not.toContainHTML('Loading Preview...');
expect(resultEl).not.toContainHTML('Download File');
});

test('should setup logo if option specifies', () => {
const url = 'http://someurl.com/';
options.logoUrl = url;
Expand Down Expand Up @@ -231,19 +245,38 @@ describe('lib/PreviewUI', () => {
});

describe('hideLoadingIndicator()', () => {
beforeEach(() => {
jest.spyOn(ui, 'showCrawler');
});

test('should hide loading indicator', () => {
const contentContainerEl = containerEl.querySelector(constants.SELECTOR_BOX_PREVIEW);
ui.hideLoadingIndicator();
expect(contentContainerEl).toHaveClass(constants.CLASS_PREVIEW_LOADED);
});

test('should show the crawler', () => {
ui.hideLoadingIndicator();
expect(ui.showCrawler).toBeCalled();
});
});

describe('showCrawler()', () => {
test('should remove the hidden class from the crawler', () => {
const crawlerEl = containerEl.querySelector(constants.SELECTOR_BOX_PREVIEW_CRAWLER_WRAPPER);
ui.hideLoadingIndicator();
ui.showCrawler();
expect(crawlerEl).not.toHaveClass(constants.CLASS_HIDDEN);
});
});

describe('hideCrawler()', () => {
test('should add the hidden class to the crawler', () => {
const crawlerEl = containerEl.querySelector(constants.SELECTOR_BOX_PREVIEW_CRAWLER_WRAPPER);
ui.hideCrawler();
expect(crawlerEl).toHaveClass(constants.CLASS_HIDDEN);
});
});

describe('setupNotification()', () => {
test('should set up the notification', () => {
ui.setupNotification();
Expand All @@ -252,6 +285,18 @@ describe('lib/PreviewUI', () => {
});
});

describe('setLoadingIcon()', () => {
test('should hide the crawler and set the file icon into the icon element', () => {
const iconEl = document.createElement('div');
iconEl.innerHTML = getIconFromExtension('pdf');

ui.setup(options);
ui.setLoadingIcon('pdf');

expect(containerEl.querySelector(constants.SELECTOR_BOX_PREVIEW_ICON).innerHTML).toEqual(iconEl.innerHTML);
});
});

describe('startProgressBar()', () => {
test('should start the progress bar', () => {
ui.progressBar = {
Expand Down
27 changes: 8 additions & 19 deletions src/lib/viewers/BaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,15 @@ import {
CLASS_ANNOTATIONS_CREATE_REGION,
CLASS_ANNOTATIONS_DISCOVERABLE,
CLASS_BOX_PREVIEW_MOBILE,
CLASS_HIDDEN,
FILE_OPTION_START,
SELECTOR_BOX_PREVIEW_BTN_ANNOTATE_DRAW,
SELECTOR_BOX_PREVIEW_BTN_ANNOTATE_POINT,
SELECTOR_BOX_PREVIEW_CONTENT,
SELECTOR_BOX_PREVIEW_CRAWLER_WRAPPER,
SELECTOR_BOX_PREVIEW_ICON,
SELECTOR_BOX_PREVIEW,
STATUS_SUCCESS,
STATUS_VIEWABLE,
} from '../constants';
import { EXCLUDED_EXTENSIONS } from '../extensions';
import { getIconFromExtension, getIconFromName } from '../icons/icons';
import { VIEWER_EVENT, ERROR_CODE, LOAD_METRIC, DOWNLOAD_REACHABILITY_METRICS } from '../events';
import AnnotationControlsFSM, { AnnotationInput, AnnotationMode } from '../AnnotationControlsFSM';
import AnnotationModule from '../AnnotationModule';
Expand Down Expand Up @@ -73,8 +69,6 @@ const ANNOTATION_BUTTONS = {
},
};

const DEFAULT_FILE_ICON_NAME = 'FILE_DEFAULT';

class BaseViewer extends EventEmitter {
/** @property {Api} - Api instance used for XHR calls */
api;
Expand Down Expand Up @@ -186,13 +180,9 @@ class BaseViewer extends EventEmitter {
}

if (this.options.file) {
const fileExt = this.options.file.extension;
this.fileLoadingIcon = getIconFromExtension(fileExt);
this.startAt = getProp(this.options, `fileOptions.${this.options.file.id}.${FILE_OPTION_START}`, {});
}

this.finishLoadingSetup();

// Get the container dom element if selector was passed, in tests
let { container } = this.options;
if (typeof container === 'string') {
Expand All @@ -204,6 +194,9 @@ class BaseViewer extends EventEmitter {
// From the perspective of viewers bp-content holds everything
this.containerEl = container.querySelector(SELECTOR_BOX_PREVIEW_CONTENT);

// Update the loading indicators
this.setupLoading();

// Attach event listeners
this.addCommonListeners();

Expand Down Expand Up @@ -235,16 +228,12 @@ class BaseViewer extends EventEmitter {
*
* @return {void}
*/
finishLoadingSetup() {
const { container } = this.options;
const crawler = container.querySelector(SELECTOR_BOX_PREVIEW_CRAWLER_WRAPPER);
if (crawler) {
crawler.classList.add(CLASS_HIDDEN);
}
setupLoading() {
const { file = {} } = this.options;

const iconWrapperEl = container.querySelector(SELECTOR_BOX_PREVIEW_ICON);
if (iconWrapperEl) {
iconWrapperEl.innerHTML = this.fileLoadingIcon || getIconFromName(DEFAULT_FILE_ICON_NAME);
if (this.previewUI) {
this.previewUI.hideCrawler();
this.previewUI.setLoadingIcon(file.extension);
}
}

Expand Down
Loading