mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Add infrastructure for managing configurable keyboard shortcuts.
This commit is contained in:
committed by
Dave Page
parent
7c985695b7
commit
66341e6947
@@ -0,0 +1,434 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
define([
|
||||
'jquery',
|
||||
'backbone',
|
||||
'pgadmin.backform',
|
||||
], function ($, Backbone, Backform) {
|
||||
describe('KeyboardshortcutControl', function () {
|
||||
let field, innerFields, control, model, event;
|
||||
|
||||
beforeEach(() => {
|
||||
|
||||
innerFields = [
|
||||
{'name': 'key', 'type': 'keyCode', 'label': 'Key'},
|
||||
{'name': 'alt_option', 'type': 'checkbox',
|
||||
'label': 'Alt/Option'},
|
||||
{'name': 'control', 'type': 'checkbox',
|
||||
'label': 'Ctrl'},
|
||||
{'name': 'shift', 'type': 'checkbox', 'label': 'Shift'},
|
||||
];
|
||||
|
||||
model = new Backbone.Model({
|
||||
'shortcut': {
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
field = new Backform.Field({
|
||||
id: 'shortcut',
|
||||
name: 'shortcut',
|
||||
control: 'keyboardShortcut',
|
||||
label: 'Keyboard shortcut',
|
||||
fields: innerFields,
|
||||
});
|
||||
|
||||
control = new (field.get('control')) ({
|
||||
field: field,
|
||||
model: model,
|
||||
});
|
||||
|
||||
control.render();
|
||||
|
||||
});
|
||||
|
||||
describe('keyboardShortcut UI setup', function () {
|
||||
|
||||
it('keyboard shortcut control should be rendered with inner fields', function () {
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('onModelChange', function () {
|
||||
beforeEach((done) => {
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
|
||||
it('when model "key" value changes UI and innerModel should update new "key" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
expect(control.innerModel.get('key')).toEqual({
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
});
|
||||
|
||||
var val = $.extend(true, {}, model.get(field.get('name')));
|
||||
|
||||
model.set(field.get('name'),
|
||||
$.extend(true, val, {
|
||||
'key': {
|
||||
'key_code': 65,
|
||||
'char': 'A',
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('A');
|
||||
expect(control.innerModel.get('key')).toEqual({
|
||||
'key_code': 65,
|
||||
'char': 'A',
|
||||
});
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('alt_option')).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('control')).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
expect(control.innerModel.get('shift')).toBeFalsy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when model "control" value changes UI and innerModel should update new "control" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('control')).toBeTruthy();
|
||||
|
||||
var val = $.extend(true, {}, model.get(field.get('name')));
|
||||
|
||||
model.set(field.get('name'),
|
||||
$.extend(true, val, {
|
||||
'control': false
|
||||
})
|
||||
);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeFalsy();
|
||||
expect(control.innerModel.get('control')).toBeFalsy();
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('alt_option')).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
expect(control.innerModel.get('key')).toEqual({
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
});
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
expect(control.innerModel.get('shift')).toBeFalsy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when model "shift" value changes UI and innerModel should update new "shift" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
expect(control.innerModel.get('shift')).toBeFalsy();
|
||||
|
||||
var val = $.extend(true, {}, model.get(field.get('name')));
|
||||
|
||||
model.set(field.get('name'),
|
||||
$.extend(true, val, {
|
||||
'shift': true
|
||||
})
|
||||
);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('shift')).toBeTruthy();
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('alt_option')).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
expect(control.innerModel.get('key')).toEqual({
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
});
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('control')).toBeTruthy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when model "alt_option" value changes UI and innerModel should update new "alt_option" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('alt_option')).toBeTruthy();
|
||||
|
||||
var val = $.extend(true, {}, model.get(field.get('name')));
|
||||
|
||||
model.set(field.get('name'),
|
||||
$.extend(true, val, {
|
||||
'alt_option': false
|
||||
})
|
||||
);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeFalsy();
|
||||
expect(control.innerModel.get('alt_option')).toBeFalsy();
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
expect(control.innerModel.get('shift')).toBeFalsy();
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
expect(control.innerModel.get('key')).toEqual({
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
});
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
expect(control.innerModel.get('control')).toBeTruthy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('onInnerModelChange', function () {
|
||||
beforeEach((done) => {
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
|
||||
it('when innerModel "key" value changes UI and model should update new "key" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
control.innerModel.set('key',
|
||||
{
|
||||
'key_code': 65,
|
||||
'char': 'A',
|
||||
}
|
||||
);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('A');
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 65,
|
||||
'char': 'A',
|
||||
},
|
||||
});
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when innerModel "control" value changes UI and model should update new "control" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
control.innerModel.set('control', false);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeFalsy();
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': false,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when innerModel "shift" value changes UI and model should update new "shift" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
control.innerModel.set('shift', true);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeTruthy();
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': true,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when innerModel "alt_option" value changes UI and model should update new "alt_option" value', function (done) {
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeTruthy();
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': true,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
control.innerModel.set('alt_option', false);
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
// this should change
|
||||
expect(control.$el.find('input:checkbox[name="alt_option"]')[0].checked).toBeFalsy();
|
||||
expect(model.get(field.get('name'))).toEqual({
|
||||
'control': true,
|
||||
'shift': false,
|
||||
'alt_option': false,
|
||||
'key': {
|
||||
'key_code': 73,
|
||||
'char': 'I',
|
||||
},
|
||||
});
|
||||
|
||||
// below three should not change.
|
||||
expect(control.$el.find('input:checkbox[name="shift"]')[0].checked).toBeFalsy();
|
||||
|
||||
expect(control.$el.find('input:text[name="key"]')[0].value).toBe('I');
|
||||
|
||||
expect(control.$el.find('input:checkbox[name="control"]')[0].checked).toBeTruthy();
|
||||
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('remove keyboardShortcut control', function () {
|
||||
|
||||
beforeEach(function() {
|
||||
|
||||
spyOn(control, 'cleanup').and.callThrough();
|
||||
|
||||
});
|
||||
|
||||
it('when removed it should remove all of it\' controls', function () {
|
||||
|
||||
control.remove();
|
||||
|
||||
expect(control.cleanup).toHaveBeenCalled();
|
||||
|
||||
expect(control.controls.length).toBe(0);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
199
web/regression/javascript/backform_controls/keycode_spec.js
Normal file
199
web/regression/javascript/backform_controls/keycode_spec.js
Normal file
@@ -0,0 +1,199 @@
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2018, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
define([
|
||||
'backbone',
|
||||
'pgadmin.backform',
|
||||
], function (Backbone, Backform) {
|
||||
describe('keyCodeControl', function () {
|
||||
let field, control, model, event;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new Backbone.Model({
|
||||
'key': {
|
||||
'key_code': 65,
|
||||
'char': 'A',
|
||||
}
|
||||
});
|
||||
|
||||
field = new Backform.Field({
|
||||
id: 'key',
|
||||
name: 'key',
|
||||
control: 'keyCode',
|
||||
label: 'Key',
|
||||
});
|
||||
|
||||
control = new (field.get('control')) ({
|
||||
field: field,
|
||||
model: model,
|
||||
});
|
||||
|
||||
control.render();
|
||||
|
||||
event = {
|
||||
which: -1,
|
||||
keyCode: -1,
|
||||
key: '',
|
||||
preventDefault: jasmine.createSpy('preventDefault'),
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
describe('onkeyDown', function () {
|
||||
|
||||
beforeEach((done) => {
|
||||
|
||||
spyOn(model, 'set').and.callThrough();
|
||||
|
||||
spyOn(control, 'onkeyDown').and.callThrough();
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('when key with escapeKeyCode is pressed model should not update', function (done) {
|
||||
event.which = 16;
|
||||
event.keyCode = 16;
|
||||
event.key = 'Shift';
|
||||
|
||||
control.onkeyDown(event);
|
||||
|
||||
expect(control.onkeyDown).toHaveBeenCalled();
|
||||
|
||||
expect(model.set).not.toHaveBeenCalled();
|
||||
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
|
||||
expect(model.get('key')).toEqual({
|
||||
'key_code': 65,
|
||||
'char': 'A',
|
||||
});
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
expect(control.$el.find('input')[0].value).toBe('A');
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when key other than escapeKeyCode is pressed model should update', function (done) {
|
||||
event.which = 66;
|
||||
event.keyCode = 66;
|
||||
event.key = 'B';
|
||||
|
||||
control.onkeyDown(event);
|
||||
|
||||
expect(control.onkeyDown).toHaveBeenCalled();
|
||||
|
||||
expect(model.set).toHaveBeenCalled();
|
||||
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
|
||||
expect(model.get('key')).toEqual({
|
||||
'key_code': 66,
|
||||
'char': 'B',
|
||||
});
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
expect(control.$el.find('input')[0].value).toBe('B');
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('onkeyUp', function () {
|
||||
|
||||
beforeEach((done) => {
|
||||
spyOn(control, 'preventEvent').and.callThrough();
|
||||
|
||||
event.stopPropagation = jasmine.createSpy('stopPropagation');
|
||||
|
||||
event.stopImmediatePropagation = jasmine.createSpy('stopImmediatePropagation');
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
|
||||
it('when key with escapeKeyCode is pressed and released event should be propagated', function (done) {
|
||||
event.which = 17;
|
||||
event.keyCode = 17;
|
||||
event.key = 'Ctrl';
|
||||
|
||||
control.preventEvent(event);
|
||||
|
||||
expect(control.preventEvent).toHaveBeenCalled();
|
||||
|
||||
expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
|
||||
expect(event.stopPropagation).not.toHaveBeenCalled();
|
||||
|
||||
expect(event.stopImmediatePropagation).not.toHaveBeenCalled();
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
expect(control.$el.find('input')[0].value).toBe('A');
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
it('when key other than escapeKeyCode is pressed and released event should not be propagated', function (done) {
|
||||
event.which = 66;
|
||||
event.keyCode = 66;
|
||||
event.key = 'B';
|
||||
|
||||
control.preventEvent(event);
|
||||
|
||||
expect(control.preventEvent).toHaveBeenCalled();
|
||||
|
||||
expect(event.preventDefault).toHaveBeenCalled();
|
||||
|
||||
expect(event.stopPropagation).toHaveBeenCalled();
|
||||
|
||||
expect(event.stopImmediatePropagation).toHaveBeenCalled();
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
expect(control.$el.find('input')[0].value).toBe('A');
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('onModelChange', function () {
|
||||
beforeEach((done) => {
|
||||
|
||||
done();
|
||||
|
||||
});
|
||||
|
||||
it('when model changes UI should update', function (done) {
|
||||
|
||||
expect(control.$el.find('input')[0].value).toBe('A');
|
||||
|
||||
model.set('key', {
|
||||
'key_code': 67,
|
||||
'char': 'C',
|
||||
});
|
||||
|
||||
// wait until UI updates.
|
||||
setTimeout(function() {
|
||||
expect(control.$el.find('input')[0].value).toBe('C');
|
||||
done();
|
||||
}, 100);
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user