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(annotations): add ftux cursor logic #1281

Merged
merged 16 commits into from
Nov 10, 2020
Merged
Show file tree
Hide file tree
Changes from 15 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/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ export const CLASS_ACTIVE = 'bp-is-active';
export const CLASS_ANNOTATIONS_CREATE_HIGHLIGHT = 'bp-annotations-create--highlight';
export const CLASS_ANNOTATIONS_CREATE_REGION = 'bp-annotations-create--region';
export const CLASS_ANNOTATIONS_DISCOVERABLE = 'bp-annotations-discoverable';
export const CLASS_ANNOTATIONS_IMAGE_FTUX_CURSOR_SEEN = 'bp-annotations-ftux-image-cursor-seen';
export const CLASS_ANNOTATIONS_DOCUMENT_FTUX_CURSOR_SEEN = 'bp-annotations-ftux-document-cursor-seen';
export const CLASS_NAVIGATION_VISIBILITY = 'bp-is-navigation-visible';
export const CLASS_HIDDEN = 'bp-is-hidden';
export const CLASS_PREVIEW_LOADED = 'bp-loaded';
Expand Down Expand Up @@ -152,3 +154,7 @@ export const METADATA = {

// Error Codes
export const ERROR_CODE_403_FORBIDDEN_BY_POLICY = 'forbidden_by_policy';

// LocalStorage Keys
export const DOCUMENT_FTUX_CURSOR_SEEN_KEY = 'bp-ftux-cursor-seen-document';
export const IMAGE_FTUX_CURSOR_SEEN_KEY = 'bp-ftux-cursor-seen-image';
22 changes: 22 additions & 0 deletions src/lib/viewers/doc/DocBaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ZoomControls from '../../ZoomControls';
import { AnnotationInput, AnnotationState } from '../../AnnotationControlsFSM';
import {
ANNOTATOR_EVENT,
CLASS_ANNOTATIONS_DOCUMENT_FTUX_CURSOR_SEEN,
CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE_ACTIVE,
CLASS_BOX_PREVIEW_THUMBNAILS_CLOSE,
CLASS_BOX_PREVIEW_THUMBNAILS_CONTAINER,
Expand All @@ -26,6 +27,7 @@ import {
CLASS_IS_SCROLLABLE,
DISCOVERABILITY_ATTRIBUTE,
DOC_STATIC_ASSETS_VERSION,
DOCUMENT_FTUX_CURSOR_SEEN_KEY,
ENCODING_TYPES,
PERMISSION_DOWNLOAD,
PRELOAD_REP_NAME,
Expand Down Expand Up @@ -105,6 +107,7 @@ class DocBaseViewer extends BaseViewer {
super(options);

// Bind context for callbacks
this.applyCursorFtux = this.applyCursorFtux.bind(this);
this.emitMetric = this.emitMetric.bind(this);
this.handleAssetAndRepLoad = this.handleAssetAndRepLoad.bind(this);
this.handleFindBarClose = this.handleFindBarClose.bind(this);
Expand All @@ -128,6 +131,7 @@ class DocBaseViewer extends BaseViewer {
this.zoomIn = this.zoomIn.bind(this);
this.zoomOut = this.zoomOut.bind(this);

this.annotationControlsFSM.subscribe(this.applyCursorFtux);
this.annotationControlsFSM.subscribe(this.updateDiscoverabilityResinTag);
}

Expand Down Expand Up @@ -1677,6 +1681,24 @@ class DocBaseViewer extends BaseViewer {
// in which the default discoverability experience is enabled
this.containerEl.setAttribute(DISCOVERABILITY_ATTRIBUTE, isUsingDiscoverability);
}

/**
* Hides the create region cursor popup for a document
*
* @protected
* @return {void}
*/
applyCursorFtux() {
if (!this.containerEl || this.annotationControlsFSM.getState() !== AnnotationState.REGION) {
return;
}

if (this.cache.get(DOCUMENT_FTUX_CURSOR_SEEN_KEY)) {
this.containerEl.classList.add(CLASS_ANNOTATIONS_DOCUMENT_FTUX_CURSOR_SEEN);
} else {
this.cache.set(DOCUMENT_FTUX_CURSOR_SEEN_KEY, true, true);
}
}
}

export default DocBaseViewer;
40 changes: 40 additions & 0 deletions src/lib/viewers/doc/__tests__/DocBaseViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ import * as util from '../../../util';
import {
ANNOTATOR_EVENT,
CLASS_HIDDEN,
DOCUMENT_FTUX_CURSOR_SEEN_KEY,
PERMISSION_DOWNLOAD,
STATUS_ERROR,
STATUS_PENDING,
STATUS_SUCCESS,
QUERY_PARAM_ENCODING,
ENCODING_TYPES,
SELECTOR_BOX_PREVIEW_CONTENT,
CLASS_ANNOTATIONS_DOCUMENT_FTUX_CURSOR_SEEN,
CLASS_BOX_PREVIEW_THUMBNAILS_CONTAINER,
CLASS_BOX_PREVIEW_THUMBNAILS_OPEN,
SELECTOR_BOX_PREVIEW,
Expand Down Expand Up @@ -2883,6 +2885,11 @@ describe('src/lib/viewers/doc/DocBaseViewer', () => {
toggleAnnotationMode: jest.fn(),
};
docBase.processAnnotationModeChange = jest.fn();
docBase.applyCursorFtux = jest.fn();
docBase.cache = {
get: jest.fn(),
set: jest.fn(),
};
});

test('should call toggleAnnotationMode and processAnnotationModeChange', () => {
Expand Down Expand Up @@ -2964,5 +2971,38 @@ describe('src/lib/viewers/doc/DocBaseViewer', () => {
},
);
});

describe('applyCursorFtux()', () => {
beforeEach(() => {
docBase.containerEl = {
classList: {
add: jest.fn(),
remove: jest.fn(),
},
removeEventListener: jest.fn(),
};
docBase.annotationControlsFSM = new AnnotationControlsFSM(AnnotationState.REGION);
docBase.cache = {
get: jest.fn(),
set: jest.fn(),
};
});

test('should add CLASS_ANNOTATIONS_DOCUMENT_FTUX_CURSOR_SEEN to the container classList if the cache contains DOCUMENT_FTUX_CURSOR_SEEN_KEY', () => {
docBase.cache.get = jest.fn().mockImplementation(() => true);

docBase.applyCursorFtux();

expect(docBase.containerEl.classList.add).toBeCalledWith(CLASS_ANNOTATIONS_DOCUMENT_FTUX_CURSOR_SEEN);
});

test('should set DOCUMENT_FTUX_CURSOR_SEEN_KEY in cache if cache does not contain DOCUMENT_FTUX_CURSOR_SEEN_KEY', () => {
docBase.cache.get = jest.fn().mockImplementation(() => false);

docBase.applyCursorFtux();

expect(docBase.cache.set).toBeCalledWith(DOCUMENT_FTUX_CURSOR_SEEN_KEY, true, true);
});
});
});
});
6 changes: 6 additions & 0 deletions src/lib/viewers/doc/_docBase.scss
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ $thumbnail-sidebar-width: 226px;
@include bp-annotations-disable-highlight-targets;
@include bp-annotations-disable-region-targets;

&.bp-annotations-ftux-document-cursor-seen {
.ba-PopupCursor {
display: none;
}
}

.textLayer span {
pointer-events: none;
}
Expand Down
8 changes: 8 additions & 0 deletions src/lib/viewers/image/Image.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,11 @@
display: block;
width: 100%;
}

.bp-content {
&.bp-annotations-create--region.bp-annotations-ftux-image-cursor-seen {
.ba-PopupCursor {
display: none;
}
}
}
27 changes: 26 additions & 1 deletion src/lib/viewers/image/ImageViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import AnnotationControls, { AnnotationMode } from '../../AnnotationControls';
import AnnotationControlsFSM, { AnnotationInput, AnnotationState, stateModeMap } from '../../AnnotationControlsFSM';
import ImageBaseViewer from './ImageBaseViewer';
import ImageControls from './ImageControls';
import { CLASS_INVISIBLE, DISCOVERABILITY_ATTRIBUTE } from '../../constants';
import {
CLASS_ANNOTATIONS_IMAGE_FTUX_CURSOR_SEEN,
CLASS_INVISIBLE,
DISCOVERABILITY_ATTRIBUTE,
IMAGE_FTUX_CURSOR_SEEN_KEY,
} from '../../constants';
import { ICON_FULLSCREEN_IN, ICON_FULLSCREEN_OUT, ICON_ROTATE_LEFT } from '../../icons/icons';
import './Image.scss';

Expand All @@ -18,6 +23,7 @@ class ImageViewer extends ImageBaseViewer {
this.api = options.api;

// Bind context for callbacks
this.applyCursorFtux = this.applyCursorFtux.bind(this);
this.getViewportDimensions = this.getViewportDimensions.bind(this);
this.handleAnnotationControlsClick = this.handleAnnotationControlsClick.bind(this);
this.handleAnnotationCreateEvent = this.handleAnnotationCreateEvent.bind(this);
Expand All @@ -32,6 +38,7 @@ class ImageViewer extends ImageBaseViewer {
this.options.enableAnnotationsImageDiscoverability ? AnnotationState.REGION_TEMP : AnnotationState.NONE,
);

this.annotationControlsFSM.subscribe(this.applyCursorFtux);
this.annotationControlsFSM.subscribe(this.updateDiscoverabilityResinTag);

if (this.isMobile) {
Expand Down Expand Up @@ -569,6 +576,24 @@ class ImageViewer extends ImageBaseViewer {
// in which the default discoverability experience is enabled
this.containerEl.setAttribute(DISCOVERABILITY_ATTRIBUTE, isUsingDiscoverability);
}

/**
* Hides the create region cursor popup for an image
*
* @protected
* @return {void}
*/
applyCursorFtux() {
if (!this.containerEl || this.annotationControlsFSM.getState() !== AnnotationState.REGION) {
return;
}

if (this.cache.get(IMAGE_FTUX_CURSOR_SEEN_KEY)) {
this.containerEl.classList.add(CLASS_ANNOTATIONS_IMAGE_FTUX_CURSOR_SEEN);
} else {
this.cache.set(IMAGE_FTUX_CURSOR_SEEN_KEY, true, true);
}
}
}

export default ImageViewer;
34 changes: 34 additions & 0 deletions src/lib/viewers/image/__tests__/ImageViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Browser from '../../../Browser';
import ControlsRoot from '../../controls/controls-root';
import ImageControls from '../ImageControls';
import ImageViewer from '../ImageViewer';
import { CLASS_ANNOTATIONS_IMAGE_FTUX_CURSOR_SEEN, IMAGE_FTUX_CURSOR_SEEN_KEY } from '../../../constants';

jest.mock('../../controls/controls-root');

Expand Down Expand Up @@ -43,6 +44,10 @@ describe('lib/viewers/image/ImageViewer', () => {
Object.defineProperty(BaseViewer.prototype, 'setup', { value: jest.fn() });
image.containerEl = containerEl;
image.options.enableAnnotationsImageDiscoverability = false;
image.cache = {
get: jest.fn(),
set: jest.fn(),
};
image.setup();
});

Expand Down Expand Up @@ -839,4 +844,33 @@ describe('lib/viewers/image/ImageViewer', () => {
expect(image.annotator.emit).toBeCalledWith('annotations_active_set', '123');
});
});

describe('applyCursorFtux()', () => {
beforeEach(() => {
image.containerEl = {
classList: {
add: jest.fn(),
remove: jest.fn(),
},
removeEventListener: jest.fn(),
};
image.annotationControlsFSM = new AnnotationControlsFSM(AnnotationState.REGION);
});

test('should add CLASS_ANNOTATIONS_IMAGE_FTUX_CURSOR_SEEN to the container classList if the cache contains IMAGE_FTUX_CURSOR_SEEN_KEY', () => {
image.cache.get = jest.fn().mockImplementation(() => true);

image.applyCursorFtux();

expect(image.containerEl.classList.add).toBeCalledWith(CLASS_ANNOTATIONS_IMAGE_FTUX_CURSOR_SEEN);
});

test('should set IMAGE_FTUX_CURSOR_SEEN_KEY in cache if the cache does not contain IMAGE_FTUX_CURSOR_SEEN_KEY', () => {
image.cache.get = jest.fn().mockImplementation(() => false);

image.applyCursorFtux();

expect(image.cache.set).toBeCalledWith(IMAGE_FTUX_CURSOR_SEEN_KEY, true, true);
});
});
});