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

Adds logic for handling up and down arrows to navigate the editor. #2094

Open
wants to merge 2 commits into
base: dev/32-pigeonite
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion docker/obojobo-pm2-server-src/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obojobo-pm2-server-app",
"version": "16.0.0-alpha.0",
"version": "16.0.0",
"description": "Reference project for deploying and customizing an Obojobo Next server",
"main": "./index.js",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"packages": [
"packages/**/*"
],
"version": "16.0.0-alpha.0",
"version": "16.0.0",
"command": {
"command": {
"run": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "obojobo-next",
"version": "15.1.1",
"version": "16.0.0",
"repository": "https://github.com/ucfopen/Obojobo.git",
"homepage": "https://ucfopen.github.io/Obojobo-Docs/",
"license": "AGPL-3.0-only",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { FULL } from 'obojobo-express/server/constants'

import { Editor, Transforms } from 'slate'
import { ReactEditor } from 'slate-react'
// jest.mock('slate')
jest.mock('src/scripts/viewer/util/editor-api')
jest.mock('src/scripts/common/util/modal-util')
jest.mock('src/scripts/oboeditor/components/node/editor', () => ({
Expand Down Expand Up @@ -1436,4 +1435,290 @@ describe('VisualEditor', () => {

document.body.removeChild(input)
})

describe('keyboard navigation', () => {
const editorChildren = JSON.stringify([
{ children: [{ text: 'Header [0,0]' }] },
{ children: [{ children: [{ text: 'Text before excerpt [1,0,0]' }] }] },
{
children: [
{
children: [
{ children: [{ text: 'Excerpt Header [2,0,0,0]' }] },
{ children: [{ children: [{ text: 'Initial Excerpt Text [2,0,1,0,0]' }] }] },
{
content: { numCols: 2, numRows: 2 },
children: [
{
content: { numCols: 2 },
children: [
{ children: [{ text: 'Table Header A [2,0,2,0,0,0]' }] },
{ children: [{ text: 'Table Header B [2,0,2,0,1,0]' }] }
]
},
{
content: { numCols: 2 },
children: [
{ children: [{ text: 'Cell A [2,0,2,1,0,0]' }] },
{ children: [{ text: 'Cell B [2,0,2,1,1,0]' }] }
]
}
]
}
]
},
{ children: [{ children: [{ text: 'Excerpt Caption [2,1,0,0]' }] }] }
]
},
{ children: [{ children: [{ text: 'Text after the excerpt [3,0,0]' }] }] }
])

const pathToSelection = path => {
return { anchor: { path: path, offset: 0 }, focus: { path: path, offset: 0 } }
}

let component
let instance
// eslint-disable-next-line prefer-const
let keyDownEvent = {
preventDefault: jest.fn(),
defaultPrevented: false,
referredFromTable: false
}

jest.spyOn(VisualEditor.prototype, 'globalPluginsOverrideKeypress').mockReturnValue(false)
jest.spyOn(VisualEditor.prototype, 'localPluginsOverrideKeypress').mockReturnValue(false)
jest.spyOn(Transforms, 'setSelection').mockImplementation((editor, range) => {
editor.prevSelection = JSON.parse(JSON.stringify(editor.selection || {}))
editor.selection = JSON.parse(JSON.stringify(range))
})

test('Up arrow: from the top node should not change the selection location', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([0, 0])
})

test('Down arrow: from the bottom node should not change the selection location', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [3, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([3, 0, 0])
})

test('Up arrow: from one node to a sibling node of the same depth', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([0, 0])
})

test('Down arrow: from one node to a sibling node of the same depth', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([1, 0, 0])
})

test('Up arrow: from one node inside an excerpt to a node outside the excerpt', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 0, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([1, 0, 0])
})

test('Down arrow: from one node outside an excerpt to a node inside the excerpt', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 0, 0, 0])
})

test('Up arrow: from one node inside an excerpt to a sibling node inside the excerpt', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 0, 1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 0, 0, 0])
})

test('Down arrow: from one node inside an excerpt to a sibling node inside the excerpt', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 0, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 0, 1, 0, 0])
})

test('Up arrow: from the first node below an excerpt to the bottom node inside', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [3, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 1, 0, 0])
})

test('Down arrow: from the bottom node inside an excerpt to the first below', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([3, 0, 0])
})

test('Up arrow: from the first node below a table to the last cell inside', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 0, 2, 1, 1, 0])
})

test('Down arrow: from the last node above a table to the first cell inside', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 0, 1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 0, 2, 0, 0, 0])
})

test('Up arrow: from the first row of a table to the last node above', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 0, 2, 0, 1, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
keyDownEvent.referredFromTable = true
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 0, 1, 0, 0])
})

test('Down arrow: from the last row of a table to the first node below', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [2, 0, 2, 1, 0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowDown'
keyDownEvent.referredFromTable = true
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([2, 1, 0, 0])
})

test('Up arrow: invalid starting path (too short)', () => {
component = mount(<VisualEditor {...props} />)
instance = component.instance()
instance.editor.children = JSON.parse(editorChildren)

const startingPath = [0, 0]
const startingSelection = pathToSelection(startingPath)
Transforms.setSelection(instance.editor, startingSelection)

keyDownEvent.key = 'ArrowUp'
keyDownEvent.referredFromTable = true // This is pop some of the length off of the initial path inappropriately
instance.onKeyDown(keyDownEvent)

expect(instance.editor.selection.anchor.path).toEqual([0, 0])
})
})
})
2 changes: 1 addition & 1 deletion packages/app/obojobo-document-engine/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obojobo-document-engine",
"version": "16.0.0-alpha.0",
"version": "16.0.0",
"license": "AGPL-3.0-only",
"description": "",
"engines": {
Expand Down
Loading