Merge pull request #6744 from edx/anton/edxnotes-caret-navigation
TNL-716: Add possibility for notes creation via keyboard.
This commit is contained in:
@@ -8,7 +8,7 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
_.bindAll(this,
|
||||
'addAriaAttributes', 'onHighlightKeyDown', 'onViewerKeyDown',
|
||||
'onEditorKeyDown', 'addDescriptions', 'removeDescription',
|
||||
'saveCurrentHighlight', 'focusOnGrabber', 'showViewer', 'onClose'
|
||||
'focusOnGrabber', 'showViewer', 'onClose', 'focusOnHighlightedText'
|
||||
);
|
||||
// Call the Annotator.Plugin constructor this sets up the element and
|
||||
// options properties.
|
||||
@@ -20,6 +20,7 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
this.annotator.subscribe('annotationViewerTextField', this.addAriaAttributes);
|
||||
this.annotator.subscribe('annotationsLoaded', this.addDescriptions);
|
||||
this.annotator.subscribe('annotationCreated', this.addDescriptions);
|
||||
this.annotator.subscribe('annotationCreated', this.focusOnHighlightedText);
|
||||
this.annotator.subscribe('annotationDeleted', this.removeDescription);
|
||||
this.annotator.element.on('keydown.accessibility.hl', '.annotator-hl', this.onHighlightKeyDown);
|
||||
this.annotator.element.on('keydown.accessibility.viewer', '.annotator-viewer', this.onViewerKeyDown);
|
||||
@@ -32,10 +33,10 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
this.annotator.unsubscribe('annotationViewerTextField', this.addAriaAttributes);
|
||||
this.annotator.unsubscribe('annotationsLoaded', this.addDescriptions);
|
||||
this.annotator.unsubscribe('annotationCreated', this.addDescriptions);
|
||||
this.annotator.unsubscribe('annotationCreated', this.focusOnHighlightedText);
|
||||
this.annotator.unsubscribe('annotationDeleted', this.removeDescription);
|
||||
this.annotator.element.off('.accessibility');
|
||||
this.removeFocusGrabber();
|
||||
this.savedHighlights = null;
|
||||
},
|
||||
|
||||
addTabIndex: function () {
|
||||
@@ -98,17 +99,19 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
});
|
||||
},
|
||||
|
||||
saveCurrentHighlight: function (annotation) {
|
||||
if (annotation && annotation.highlights) {
|
||||
this.savedHighlights = annotation.highlights[0];
|
||||
}
|
||||
},
|
||||
|
||||
focusOnHighlightedText: function () {
|
||||
if (this.savedHighlights) {
|
||||
this.savedHighlights.focus();
|
||||
this.savedHighlights = null;
|
||||
}
|
||||
var viewer = this.annotator.viewer,
|
||||
editor = this.annotator.editor,
|
||||
highlight;
|
||||
|
||||
try {
|
||||
if (viewer.isShown()) {
|
||||
highlight = viewer.annotations[0].highlights[0];
|
||||
} else if (editor.isShown()) {
|
||||
highlight = editor.annotation.highlights[0];
|
||||
}
|
||||
highlight.focus();
|
||||
} catch (err) {}
|
||||
},
|
||||
|
||||
getViewerTabControls: function () {
|
||||
@@ -168,7 +171,6 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
|
||||
showViewer: function (position, annotation) {
|
||||
annotation = $.makeArray(annotation);
|
||||
this.saveCurrentHighlight(annotation[0]);
|
||||
this.annotator.showViewer(annotation, position);
|
||||
this.annotator.element.find('.annotator-listing').focus();
|
||||
this.annotator.subscribe('annotationDeleted', this.focusOnGrabber);
|
||||
@@ -190,6 +192,8 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
// This happens only when coming from notes page
|
||||
if (this.annotator.viewer.isShown()) {
|
||||
this.annotator.element.find('.annotator-listing').focus();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case KEY.ENTER:
|
||||
@@ -197,17 +201,16 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
if (!this.annotator.viewer.isShown()) {
|
||||
position = target.position();
|
||||
this.showViewer(position, target.data('annotation'));
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
break;
|
||||
case KEY.ESCAPE:
|
||||
this.annotator.viewer.hide();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
}
|
||||
// We do not stop propagation and default behavior on a TAB keypress
|
||||
if (event.keyCode !== KEY.TAB || (event.keyCode === KEY.TAB && this.annotator.viewer.isShown())) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
},
|
||||
|
||||
onViewerKeyDown: function (event) {
|
||||
@@ -241,14 +244,14 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
case KEY.ENTER:
|
||||
case KEY.SPACE:
|
||||
if (target.hasClass('annotator-close')) {
|
||||
this.annotator.viewer.hide();
|
||||
this.onClose();
|
||||
this.annotator.viewer.hide();
|
||||
event.preventDefault();
|
||||
}
|
||||
break;
|
||||
case KEY.ESCAPE:
|
||||
this.annotator.viewer.hide();
|
||||
this.onClose();
|
||||
this.annotator.viewer.hide();
|
||||
event.preventDefault();
|
||||
break;
|
||||
}
|
||||
@@ -288,29 +291,31 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
break;
|
||||
case KEY.ENTER:
|
||||
if (target.is(save) || event.metaKey || event.ctrlKey) {
|
||||
this.onClose();
|
||||
this.annotator.editor.submit();
|
||||
} else if (target.is(cancel)) {
|
||||
this.onClose();
|
||||
this.annotator.editor.hide();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
this.onClose();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case KEY.SPACE:
|
||||
if (target.is(save)) {
|
||||
this.onClose();
|
||||
this.annotator.editor.submit();
|
||||
} else if (target.is(cancel)) {
|
||||
this.onClose();
|
||||
this.annotator.editor.hide();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
this.onClose();
|
||||
event.preventDefault();
|
||||
break;
|
||||
case KEY.ESCAPE:
|
||||
this.annotator.editor.hide();
|
||||
this.onClose();
|
||||
this.annotator.editor.hide();
|
||||
event.preventDefault();
|
||||
break;
|
||||
}
|
||||
|
||||
117
lms/static/js/edxnotes/plugins/caret_navigation.js
Normal file
117
lms/static/js/edxnotes/plugins/caret_navigation.js
Normal file
@@ -0,0 +1,117 @@
|
||||
;(function (define, undefined) {
|
||||
'use strict';
|
||||
define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
/**
|
||||
* The CaretNavigation Plugin which allows notes creation when users use
|
||||
* caret navigation to select the text.
|
||||
* Use `Ctrl + SPACE` or `Ctrl + ENTER` to open the editor.
|
||||
**/
|
||||
Annotator.Plugin.CaretNavigation = function () {
|
||||
// Call the Annotator.Plugin constructor this sets up the element and
|
||||
// options properties.
|
||||
_.bindAll(this, 'onKeyUp');
|
||||
Annotator.Plugin.apply(this, arguments);
|
||||
};
|
||||
|
||||
$.extend(Annotator.Plugin.CaretNavigation.prototype, new Annotator.Plugin(), {
|
||||
pluginInit: function () {
|
||||
$(document).on('keyup', this.onKeyUp);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
$(document).off('keyup', this.onKeyUp);
|
||||
},
|
||||
|
||||
isShortcut: function (event) {
|
||||
// Character ']' has keyCode 221
|
||||
return event.keyCode === 221 && event.ctrlKey && event.shiftKey;
|
||||
},
|
||||
|
||||
hasSelection: function (ranges) {
|
||||
return (ranges || []).length;
|
||||
},
|
||||
|
||||
saveSelection: function () {
|
||||
this.savedRange = Annotator.Util.getGlobal().getSelection().getRangeAt(0);
|
||||
},
|
||||
|
||||
restoreSelection: function () {
|
||||
if (this.savedRange) {
|
||||
var browserRange = new Annotator.Range.BrowserRange(this.savedRange),
|
||||
normedRange = browserRange.normalize().limit(this.annotator.wrapper[0]);
|
||||
|
||||
Annotator.Util.readRangeViaSelection(normedRange);
|
||||
this.savedRange = null;
|
||||
}
|
||||
},
|
||||
|
||||
onKeyUp: function (event) {
|
||||
var annotator = this.annotator,
|
||||
self = this,
|
||||
isAnnotator, annotation, highlights, position, save, cancel, cleanup;
|
||||
|
||||
// Do nothing if not a shortcut.
|
||||
if (!this.isShortcut(event)) {
|
||||
return true;
|
||||
}
|
||||
// Get the currently selected ranges.
|
||||
annotator.selectedRanges = annotator.getSelectedRanges();
|
||||
// Do nothing if there is no selection
|
||||
if (!this.hasSelection(annotator.selectedRanges)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
isAnnotator = _.some(annotator.selectedRanges, function (range) {
|
||||
return annotator.isAnnotator(range.commonAncestor);
|
||||
});
|
||||
|
||||
// Do nothing if we are in Annotator.
|
||||
if (isAnnotator) {
|
||||
return true;
|
||||
}
|
||||
// Show a temporary highlight so the user can see what they selected
|
||||
// Also extract the quotation and serialize the ranges
|
||||
annotation = annotator.setupAnnotation(annotator.createAnnotation());
|
||||
highlights = $(annotation.highlights).addClass('annotator-hl-temporary');
|
||||
|
||||
if (annotator.adder.is(':visible')) {
|
||||
position = annotator.adder.position();
|
||||
annotator.adder.hide();
|
||||
} else {
|
||||
position = highlights.last().position();
|
||||
}
|
||||
|
||||
// Subscribe to the editor events
|
||||
// Make the highlights permanent if the annotation is saved
|
||||
save = function () {
|
||||
cleanup();
|
||||
highlights.removeClass('annotator-hl-temporary');
|
||||
// Fire annotationCreated events so that plugins can react to them
|
||||
annotator.publish('annotationCreated', [annotation]);
|
||||
};
|
||||
|
||||
// Remove the highlights if the edit is cancelled
|
||||
cancel = function () {
|
||||
self.restoreSelection();
|
||||
cleanup();
|
||||
annotator.deleteAnnotation(annotation);
|
||||
};
|
||||
|
||||
// Don't leak handlers at the end
|
||||
cleanup = function () {
|
||||
annotator.unsubscribe('annotationEditorHidden', cancel);
|
||||
annotator.unsubscribe('annotationEditorSubmit', save);
|
||||
self.savedRange = null;
|
||||
};
|
||||
|
||||
annotator.subscribe('annotationEditorHidden', cancel);
|
||||
annotator.subscribe('annotationEditorSubmit', save);
|
||||
|
||||
this.saveSelection();
|
||||
// Display the editor.
|
||||
annotator.showEditor(annotation, position);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -47,13 +47,10 @@ define(['jquery', 'underscore', 'annotator_1.2.9'], function ($, _, Annotator) {
|
||||
highlight = $(note.highlights[0]);
|
||||
offset = highlight.position();
|
||||
// Open the note
|
||||
this.annotator.plugins.Accessibility.showViewer(
|
||||
{
|
||||
top: offset.top + 0.5 * highlight.height(),
|
||||
left: offset.left + 0.5 * highlight.width()
|
||||
},
|
||||
note
|
||||
);
|
||||
this.annotator.showFrozenViewer([note], {
|
||||
top: offset.top + 0.5 * highlight.height(),
|
||||
left: offset.left + 0.5 * highlight.width()
|
||||
});
|
||||
// Freeze the viewer
|
||||
this.annotator.freezeAll();
|
||||
// Scroll to highlight
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
define([
|
||||
'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/utils/logger',
|
||||
'js/edxnotes/views/shim', 'js/edxnotes/plugins/scroller',
|
||||
'js/edxnotes/plugins/events', 'js/edxnotes/plugins/accessibility'
|
||||
'js/edxnotes/plugins/events', 'js/edxnotes/plugins/accessibility',
|
||||
'js/edxnotes/plugins/caret_navigation'
|
||||
], function ($, _, Annotator, NotesLogger) {
|
||||
var plugins = ['Auth', 'Store', 'Scroller', 'Events', 'Accessibility'],
|
||||
var plugins = ['Auth', 'Store', 'Scroller', 'Events', 'Accessibility', 'CaretNavigation'],
|
||||
getOptions, setupPlugins, updateHeaders, getAnnotator;
|
||||
|
||||
/**
|
||||
|
||||
@@ -310,6 +310,12 @@ define([
|
||||
unfreezeAll: function () {
|
||||
_.invoke(Annotator._instances, 'unfreeze');
|
||||
return this;
|
||||
},
|
||||
|
||||
showFrozenViewer: function (annotations, location) {
|
||||
this.showViewer(annotations, location);
|
||||
this.freezeAll();
|
||||
return this;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -43,7 +43,7 @@ define([
|
||||
describe('destroy', function () {
|
||||
it('should unbind all events', function () {
|
||||
spyOn($.fn, 'off');
|
||||
spyOn(this.annotator, 'unsubscribe');
|
||||
spyOn(this.annotator, 'unsubscribe').andCallThrough();
|
||||
this.plugin.destroy();
|
||||
expect(this.annotator.unsubscribe).toHaveBeenCalledWith(
|
||||
'annotationViewerTextField', this.plugin.addAriaAttributes
|
||||
@@ -54,6 +54,9 @@ define([
|
||||
expect(this.annotator.unsubscribe).toHaveBeenCalledWith(
|
||||
'annotationCreated', this.plugin.addDescriptions
|
||||
);
|
||||
expect(this.annotator.unsubscribe).toHaveBeenCalledWith(
|
||||
'annotationCreated', this.plugin.focusOnHighlightedText
|
||||
);
|
||||
expect(this.annotator.unsubscribe).toHaveBeenCalledWith(
|
||||
'annotationDeleted', this.plugin.removeDescription
|
||||
);
|
||||
@@ -136,11 +139,9 @@ define([
|
||||
it('should focus highlighted text after closing', function () {
|
||||
var note;
|
||||
highlight.trigger(keyDownEvent(this.KEY.ENTER));
|
||||
expect(this.plugin.savedHighlights).toBeDefined();
|
||||
note = this.annotator.element.find('.annotator-edit');
|
||||
note.trigger(keyDownEvent(this.KEY.ESCAPE));
|
||||
expect(highlight).toBeFocused();
|
||||
expect(this.plugin.savedHighlights).toBeNull();
|
||||
});
|
||||
|
||||
it('should focus on grabber after being deleted', function () {
|
||||
|
||||
200
lms/static/js/spec/edxnotes/plugins/caret_navigation_spec.js
Normal file
200
lms/static/js/spec/edxnotes/plugins/caret_navigation_spec.js
Normal file
@@ -0,0 +1,200 @@
|
||||
define([
|
||||
'jquery', 'underscore', 'annotator_1.2.9', 'logger', 'js/edxnotes/views/notes_factory'
|
||||
], function($, _, Annotator, Logger, NotesFactory) {
|
||||
'use strict';
|
||||
describe('EdxNotes CaretNavigation Plugin', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html');
|
||||
this.annotator = NotesFactory.factory(
|
||||
$('div#edx-notes-wrapper-123').get(0), {
|
||||
endpoint: 'http://example.com/'
|
||||
}
|
||||
);
|
||||
this.plugin = this.annotator.plugins.CaretNavigation;
|
||||
spyOn(Logger, 'log');
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
_.invoke(Annotator._instances, 'destroy');
|
||||
});
|
||||
|
||||
describe('destroy', function () {
|
||||
it('should unbind all events', function () {
|
||||
spyOn($.fn, 'off');
|
||||
this.plugin.destroy();
|
||||
expect($.fn.off).toHaveBeenCalledWith('keyup', this.plugin.onKeyUp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isShortcut', function () {
|
||||
it('should return `true` if it is a shortcut', function () {
|
||||
expect(this.plugin.isShortcut($.Event('keyup', {
|
||||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
keyCode: 221
|
||||
}))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return `false` if it is not a shortcut', function () {
|
||||
expect(this.plugin.isShortcut($.Event('keyup', {
|
||||
ctrlKey: false,
|
||||
shiftKey: true,
|
||||
keyCode: 221
|
||||
}))).toBeFalsy();
|
||||
|
||||
expect(this.plugin.isShortcut($.Event('keyup', {
|
||||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
keyCode: $.ui.keyCode.TAB
|
||||
}))).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasSelection', function () {
|
||||
it('should return `true` if has selection', function () {
|
||||
expect(this.plugin.hasSelection([{}, {}])).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return `false` if does not have selection', function () {
|
||||
expect(this.plugin.hasSelection([])).toBeFalsy();
|
||||
expect(this.plugin.hasSelection()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('onKeyUp', function () {
|
||||
var triggerEvent = function (element, props) {
|
||||
var eventProps = $.extend({
|
||||
ctrlKey: true,
|
||||
shiftKey: true,
|
||||
keyCode: 221
|
||||
}, props);
|
||||
element.trigger($.Event('keyup', eventProps));
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
this.element = $('<span />', {'class': 'annotator-hl'}).appendTo(this.annotator.element);
|
||||
|
||||
this.annotation = {
|
||||
text: "test",
|
||||
highlights: [this.element.get(0)]
|
||||
};
|
||||
|
||||
this.mockOffset = {top: 0, left:0};
|
||||
|
||||
this.mockSubscriber = jasmine.createSpy();
|
||||
this.annotator.subscribe('annotationCreated', this.mockSubscriber);
|
||||
|
||||
spyOn($.fn, 'position').andReturn(this.mockOffset);
|
||||
spyOn(this.annotator, 'createAnnotation').andReturn(this.annotation);
|
||||
spyOn(this.annotator, 'setupAnnotation').andReturn(this.annotation);
|
||||
spyOn(this.annotator, 'getSelectedRanges').andReturn([{}]);
|
||||
spyOn(this.annotator, 'deleteAnnotation');
|
||||
spyOn(this.annotator, 'showEditor');
|
||||
spyOn(Annotator.Util, 'readRangeViaSelection');
|
||||
spyOn(this.plugin, 'saveSelection');
|
||||
spyOn(this.plugin, 'restoreSelection');
|
||||
});
|
||||
|
||||
it('should create a new annotation', function () {
|
||||
triggerEvent(this.element);
|
||||
expect(this.annotator.createAnnotation.callCount).toBe(1);
|
||||
});
|
||||
|
||||
it('should set up the annotation', function () {
|
||||
triggerEvent(this.element);
|
||||
expect(this.annotator.setupAnnotation).toHaveBeenCalledWith(
|
||||
this.annotation
|
||||
);
|
||||
});
|
||||
|
||||
it('should display the Annotation#editor correctly if the Annotation#adder is hidden', function () {
|
||||
spyOn($.fn, 'is').andReturn(false);
|
||||
triggerEvent(this.element);
|
||||
expect($('annotator-hl-temporary').position.callCount).toBe(1);
|
||||
expect(this.annotator.showEditor).toHaveBeenCalledWith(
|
||||
this.annotation, this.mockOffset
|
||||
);
|
||||
});
|
||||
|
||||
it('should display the Annotation#editor in the same place as the Annotation#adder', function () {
|
||||
spyOn($.fn, 'is').andReturn(true);
|
||||
triggerEvent(this.element);
|
||||
expect(this.annotator.adder.position.callCount).toBe(1);
|
||||
expect(this.annotator.showEditor).toHaveBeenCalledWith(
|
||||
this.annotation, this.mockOffset
|
||||
);
|
||||
});
|
||||
|
||||
it('should hide the Annotation#adder', function () {
|
||||
spyOn($.fn, 'is').andReturn(true);
|
||||
spyOn($.fn, 'hide');
|
||||
triggerEvent(this.element);
|
||||
expect(this.annotator.adder.hide).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should add temporary highlights to the document to show the user what they selected', function () {
|
||||
triggerEvent(this.element);
|
||||
expect(this.element).toHaveClass('annotator-hl');
|
||||
expect(this.element).toHaveClass('annotator-hl-temporary');
|
||||
});
|
||||
|
||||
it('should persist the temporary highlights if the annotation is saved', function () {
|
||||
triggerEvent(this.element);
|
||||
this.annotator.publish('annotationEditorSubmit');
|
||||
expect(this.element).toHaveClass('annotator-hl');
|
||||
expect(this.element).not.toHaveClass('annotator-hl-temporary');
|
||||
});
|
||||
|
||||
it('should trigger the `annotationCreated` event if the edit\'s saved', function () {
|
||||
triggerEvent(this.element);
|
||||
this.annotator.onEditorSubmit(this.annotation);
|
||||
expect(this.mockSubscriber).toHaveBeenCalledWith(this.annotation);
|
||||
});
|
||||
|
||||
it('should call Annotator#deleteAnnotation if editing is cancelled', function () {
|
||||
triggerEvent(this.element);
|
||||
this.annotator.onEditorHide();
|
||||
expect(this.mockSubscriber).not.toHaveBeenCalledWith('annotationCreated');
|
||||
expect(this.annotator.deleteAnnotation).toHaveBeenCalledWith(
|
||||
this.annotation
|
||||
);
|
||||
});
|
||||
|
||||
it('should restore selection if editing is cancelled', function () {
|
||||
triggerEvent(this.element);
|
||||
this.plugin.savedRange = 'range';
|
||||
expect(this.plugin.saveSelection).toHaveBeenCalled();
|
||||
this.annotator.onEditorHide();
|
||||
expect(this.plugin.restoreSelection).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing if the edit\'s saved', function () {
|
||||
triggerEvent(this.element);
|
||||
expect(this.plugin.saveSelection).toHaveBeenCalled();
|
||||
this.plugin.savedRange = 'range';
|
||||
this.annotator.onEditorSubmit();
|
||||
expect(Annotator.Util.readRangeViaSelection).not.toHaveBeenCalled();
|
||||
expect(this.plugin.savedRange).toBeNull();
|
||||
expect(this.plugin.restoreSelection).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing if it is not a shortcut', function () {
|
||||
triggerEvent(this.element, {ctrlKey: false});
|
||||
expect(this.annotator.showEditor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing if empty selection', function () {
|
||||
this.annotator.getSelectedRanges.andReturn([]);
|
||||
triggerEvent(this.element);
|
||||
expect(this.annotator.showEditor).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should do nothing if selection is in Annotator', function () {
|
||||
spyOn(this.annotator, 'isAnnotator').andReturn(true);
|
||||
triggerEvent(this.element);
|
||||
expect(this.annotator.showEditor).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -572,6 +572,7 @@
|
||||
'lms/include/js/spec/edxnotes/plugins/accessibility_spec.js',
|
||||
'lms/include/js/spec/edxnotes/plugins/events_spec.js',
|
||||
'lms/include/js/spec/edxnotes/plugins/scroller_spec.js',
|
||||
'lms/include/js/spec/edxnotes/plugins/caret_navigation_spec.js',
|
||||
'lms/include/js/spec/edxnotes/collections/notes_spec.js',
|
||||
'lms/include/js/spec/search/search_spec.js'
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user