diff --git a/docker/obojobo-pm2-server-src/package.json b/docker/obojobo-pm2-server-src/package.json index f5fbe899a..20b8752d1 100644 --- a/docker/obojobo-pm2-server-src/package.json +++ b/docker/obojobo-pm2-server-src/package.json @@ -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, diff --git a/lerna.json b/lerna.json index af92c7967..ffd670396 100644 --- a/lerna.json +++ b/lerna.json @@ -2,7 +2,7 @@ "packages": [ "packages/**/*" ], - "version": "16.0.0-alpha.0", + "version": "16.0.0", "command": { "command": { "run": { diff --git a/package.json b/package.json index 12d53537a..40baf21ac 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/packages/app/obojobo-document-engine/__tests__/oboeditor/components/visual-editor.test.js b/packages/app/obojobo-document-engine/__tests__/oboeditor/components/visual-editor.test.js index 7bd38f546..f117adbe7 100644 --- a/packages/app/obojobo-document-engine/__tests__/oboeditor/components/visual-editor.test.js +++ b/packages/app/obojobo-document-engine/__tests__/oboeditor/components/visual-editor.test.js @@ -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', () => ({ @@ -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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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() + 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]) + }) + }) }) diff --git a/packages/app/obojobo-document-engine/package.json b/packages/app/obojobo-document-engine/package.json index 611964649..cf8359a48 100644 --- a/packages/app/obojobo-document-engine/package.json +++ b/packages/app/obojobo-document-engine/package.json @@ -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": { diff --git a/packages/app/obojobo-document-engine/src/scripts/oboeditor/components/visual-editor.js b/packages/app/obojobo-document-engine/src/scripts/oboeditor/components/visual-editor.js index d5daaca4e..19eaf7c82 100644 --- a/packages/app/obojobo-document-engine/src/scripts/oboeditor/components/visual-editor.js +++ b/packages/app/obojobo-document-engine/src/scripts/oboeditor/components/visual-editor.js @@ -94,6 +94,8 @@ class VisualEditor extends React.Component { this.markUnsaved = this.markUnsaved.bind(this) this.onKeyDownGlobal = this.onKeyDownGlobal.bind(this) this.onKeyDown = this.onKeyDown.bind(this) + this.globalPluginsOverrideKeypress = this.globalPluginsOverrideKeypress.bind(this) + this.localPluginsOverrideKeypress = this.localPluginsOverrideKeypress.bind(this) this.decorate = this.decorate.bind(this) this.renderLeaf = this.renderLeaf.bind(this) this.renameModule = this.renameModule.bind(this) @@ -337,7 +339,6 @@ class VisualEditor extends React.Component { // Save the previous selection in case the editor is unfocused // This mostly happens with MoreInfoBoxes and void nodes if (this.editor.selection) this.editor.prevSelection = this.editor.selection - this.setState({ value }) this.markUnsaved() } @@ -514,13 +515,15 @@ class VisualEditor extends React.Component { } } - // All the 'plugin' methods that allow the obonodes to extend the default functionality - onKeyDown(event) { + globalPluginsOverrideKeypress(event) { for (const plugin of this.globalPlugins) { if (plugin.onKeyDown) plugin.onKeyDown(event, this.editor) - if (event.defaultPrevented) return + if (event.defaultPrevented) return true } + return false + } + localPluginsOverrideKeypress(event) { // If none of the global plugins caught the key event, // Get each component (non-subtype) node that is selected, // and run keydown on each @@ -541,38 +544,166 @@ class VisualEditor extends React.Component { } } - // This fix breaks the default behavior when moving up inside an element. Needs to be reevaluated. - /***** - // Handle ArrowUp from a node - this is default behavior - // in Chrome and Safari but not Firefox - if (event.key === 'ArrowUp' && !event.defaultPrevented) { - event.preventDefault() + return event.defaultPrevented + } + + // All the 'plugin' methods that allow the obonodes to extend the default functionality + onKeyDown(event) { + if (this.globalPluginsOverrideKeypress(event)) return + if (this.localPluginsOverrideKeypress(event)) return + + const getElementByPath = possiblePath => { + let slateElement = this.editor + for (let i = 0; i < possiblePath.length; i++) { + if (slateElement.children && slateElement.children[possiblePath[i]]) { + slateElement = slateElement.children[possiblePath[i]] + } else { + return false + } + } + return JSON.parse(JSON.stringify(slateElement)) + } - const currentNode = this.editor.selection.anchor.path[0] + // Given a known starting path, this function finds the last child of the last child of the last child... + // of that starting path. This is so navigating with the up arrow doesn't skip over child elements. + const getLastChild = startingPath => { + if (startingPath.length === 0) { + return [0] + } - // Break out if already at top node - if (currentNode === 0) return + let slateElement = getElementByPath(startingPath) - const aboveNode = currentNode - 1 - const numChildrenAbove = this.editor.children[aboveNode].children.length + // eslint-disable-next-line prefer-const + let lengthenedPath = [...startingPath] + while (slateElement.children && slateElement.children.length > 0) { + lengthenedPath.push(slateElement.children.length - 1) + slateElement = slateElement.children[slateElement.children.length - 1] + } + return lengthenedPath + } - let abovePath = [aboveNode] + // There are several built-in functions for SlateJS Paths (like Path.next or Path.previous), but with the + // odd ordering of objects (for instance, in Excerpts and Lists), it was far more effective to build our own + // functions to compute previous and next paths given a current path. + const getPreviousPath = currentPath => { + const depth = currentPath.length - 2 + if (depth < 0) { + return false + } - // If entering a node with multiple children (a table), - // go to the last child (bottom row) - if (numChildrenAbove > 1) { - abovePath = [aboveNode, numChildrenAbove - 1] + // eslint-disable-next-line prefer-const + let nextPath = [...currentPath] + + // Case 1: Going directly to a sibling of the same depth: [12, 0, 2, 4, 0] => [12, 0, 2, 3, 0] + if (currentPath[depth] !== 0) { + nextPath[depth]-- + nextPath.pop() + return getLastChild(nextPath) } - const focus = Editor.start(this.editor, abovePath) - const anchor = Editor.start(this.editor, abovePath) + // Case 2: Going from a child with one or more additional indents: [12, 0, 2, 0, 0] => [12, 0, 1, 0] + // With multiple indents, there could be LOTS of trailing zeroes: [12, 0, 2, 0, 0, 0, 0, 0, 0] + while (nextPath[nextPath.length - 1] === 0) { + nextPath.pop() + } + nextPath[nextPath.length - 1]-- + return getLastChild(nextPath) + } + + const getNextPath = currentPath => { + let depth + let nextPath + let extendedPath + // eslint-disable-next-line prefer-const + let initialPath = [...currentPath] + + while (initialPath.length > 1) { + depth = initialPath.length - 2 + + // Check to see if there is a valid path for a direct sibling + nextPath = [...initialPath] + nextPath[depth]++ + nextPath[depth + 1] = 0 + + // Dig deeper into the sibling node: [12, 0, 1, 0] => [12, 0, 2, 0, 0, 0] (This handles excerpts and lists) + extendedPath = [...nextPath] + for (let i = 0; i < 5; i++) { + extendedPath.push(0) + if (getElementByPath(extendedPath)) { + nextPath = [...extendedPath] + } + } - Transforms.setSelection(this.editor, { - focus, - anchor - }) + if (getElementByPath(nextPath)) { + return nextPath + } + + // If there is no sibling on this level, go up to the parent level. + initialPath.pop() + } + return false + } + + // The following code checks to see if the editor should switch focus. + if (event.key === 'ArrowUp') { + /* The editor's path is an array that says where in the editor you are. + * [2, 1] = Third element, 2nd sub-element (like a row in a text box) + * [4, 2, 3] = Fifth element, 3rd sub-element (row), 4th sub-sub-element (column) + * + * A major issue is excerpts, which contain standard "root" element types (text, tables, + * lists, etc) that are all one layer deeper than expected since the excerpt itself is at + * index 0. + */ + // eslint-disable-next-line prefer-const + let currentPath = [...this.editor?.selection?.focus?.path] + + // Tables' paths have unexpected numbers of layers to account for their rows and columns. + // In order to leave the element properly, we need to pop off those layers. + if (event.referredFromTable) { + event.referredFromTable = false + currentPath.pop() + currentPath.pop() + } + + const newPath = getPreviousPath(currentPath) + if (!newPath) { + return + } + + const newPoint = Editor.start(this.editor, newPath) + const newRange = { + focus: newPoint, + anchor: newPoint + } + Transforms.setSelection(this.editor, newRange) + + event.preventDefault() + } + + // The following code checks to see if the editor should switch focus. + if (event.key === 'ArrowDown') { + // eslint-disable-next-line prefer-const + let currentPath = [...this.editor?.selection?.focus?.path] + if (event.referredFromTable) { + event.referredFromTable = false + currentPath.pop() + currentPath.pop() + } + + const newPath = getNextPath(currentPath) + if (!newPath) { + return + } + + const newPoint = Editor.start(this.editor, newPath) + const newRange = { + focus: newPoint, + anchor: newPoint + } + Transforms.setSelection(this.editor, newRange) + + event.preventDefault() } - *****/ } // Generates any necessary decorations, such as place holders diff --git a/packages/app/obojobo-document-json-parser/package.json b/packages/app/obojobo-document-json-parser/package.json index eeeec220f..6602fbce2 100644 --- a/packages/app/obojobo-document-json-parser/package.json +++ b/packages/app/obojobo-document-json-parser/package.json @@ -3,11 +3,11 @@ "xml-formatter": "^2.4.0" }, "peerDependencies": { - "obojobo-document-engine": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-document-engine": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "name": "obojobo-document-json-parser", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "main": "", "scripts": { diff --git a/packages/app/obojobo-document-xml-parser/package.json b/packages/app/obojobo-document-xml-parser/package.json index 56f701aaf..f9e38dc55 100644 --- a/packages/app/obojobo-document-xml-parser/package.json +++ b/packages/app/obojobo-document-xml-parser/package.json @@ -4,10 +4,10 @@ "xml-js": "^1.0.2" }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "name": "obojobo-document-xml-parser", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "main": "xml2draft.js", "scripts": { diff --git a/packages/app/obojobo-express/package.json b/packages/app/obojobo-express/package.json index 71d3a2511..be1ec5ae8 100644 --- a/packages/app/obojobo-express/package.json +++ b/packages/app/obojobo-express/package.json @@ -1,7 +1,7 @@ { "name": "obojobo-express", "license": "AGPL-3.0-only", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "repository": "https://github.com/ucfopen/Obojobo.git", "homepage": "https://ucfopen.github.io/Obojobo-Docs/", "description": "Obojobo express server middleware.", @@ -69,9 +69,9 @@ "uuid": "^8.3.2" }, "peerDependencies": { - "obojobo-document-engine": "^16.0.0-alpha.0", - "obojobo-document-xml-parser": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-document-engine": "^16.0.0", + "obojobo-document-xml-parser": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "devDependencies": { "@svgr/webpack": "^5.5.0", diff --git a/packages/app/obojobo-module-selector/package.json b/packages/app/obojobo-module-selector/package.json index 403b9317c..409b56602 100644 --- a/packages/app/obojobo-module-selector/package.json +++ b/packages/app/obojobo-module-selector/package.json @@ -1,7 +1,7 @@ { "name": "obojobo-module-selector", "license": "AGPL-3.0-only", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "repository": "https://github.com/ucfopen/Obojobo.git", "homepage": "https://ucfopen.github.io/Obojobo-Docs/", "description": "Obojobo package responsible for selecting which module you use in a course.", @@ -29,8 +29,8 @@ "express": "~4.18.2" }, "peerDependencies": { - "obojobo-express": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0", - "obojobo-repository": "^16.0.0-alpha.0" + "obojobo-express": "^16.0.0", + "obojobo-lib-utils": "^16.0.0", + "obojobo-repository": "^16.0.0" } } diff --git a/packages/app/obojobo-repository/package.json b/packages/app/obojobo-repository/package.json index 082e132f7..042aff348 100644 --- a/packages/app/obojobo-repository/package.json +++ b/packages/app/obojobo-repository/package.json @@ -1,7 +1,7 @@ { "name": "obojobo-repository", "license": "AGPL-3.0-only", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "repository": "https://github.com/ucfopen/Obojobo.git", "homepage": "https://ucfopen.github.io/Obojobo-Docs/", "description": "Obojobo express server middleware.", @@ -46,8 +46,8 @@ "use-debounce": "^7.0.0" }, "peerDependencies": { - "obojobo-express": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-express": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "jest": { "setupFilesAfterEnv": [ diff --git a/packages/obonode/obojobo-chunks-abstract-assessment/package.json b/packages/obonode/obojobo-chunks-abstract-assessment/package.json index d4d261090..f492ae0fb 100644 --- a/packages/obonode/obojobo-chunks-abstract-assessment/package.json +++ b/packages/obonode/obojobo-chunks-abstract-assessment/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-abstract-assessment", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "AbstractAssessment chunk for Obojobo", "scripts": { @@ -28,8 +28,8 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-chunks-question": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-chunks-question": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "devDependencies": { "lint-staged": "^10.2.2" diff --git a/packages/obonode/obojobo-chunks-action-button/package.json b/packages/obonode/obojobo-chunks-action-button/package.json index 05cdc1600..a50f70d02 100644 --- a/packages/obonode/obojobo-chunks-action-button/package.json +++ b/packages/obonode/obojobo-chunks-action-button/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-action-button", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "scripts": { "test": "TZ='America/New_York' jest --verbose", @@ -20,7 +20,7 @@ ] }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-break/package.json b/packages/obonode/obojobo-chunks-break/package.json index 2a8f67795..310cc946a 100644 --- a/packages/obonode/obojobo-chunks-break/package.json +++ b/packages/obonode/obojobo-chunks-break/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-break", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Break content chunk for Obojobo", "scripts": { @@ -21,7 +21,7 @@ ] }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-code/package.json b/packages/obonode/obojobo-chunks-code/package.json index 6329d89ae..bea55e223 100644 --- a/packages/obonode/obojobo-chunks-code/package.json +++ b/packages/obonode/obojobo-chunks-code/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-code", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Code content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-excerpt/package.json b/packages/obonode/obojobo-chunks-excerpt/package.json index 1f26897c0..953cd61dd 100644 --- a/packages/obonode/obojobo-chunks-excerpt/package.json +++ b/packages/obonode/obojobo-chunks-excerpt/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-excerpt", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Excerpt content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-figure/package.json b/packages/obonode/obojobo-chunks-figure/package.json index cc1957130..482c8bef2 100644 --- a/packages/obonode/obojobo-chunks-figure/package.json +++ b/packages/obonode/obojobo-chunks-figure/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-figure", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Figure content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-heading/package.json b/packages/obonode/obojobo-chunks-heading/package.json index 7edef4923..e6610ea36 100644 --- a/packages/obonode/obojobo-chunks-heading/package.json +++ b/packages/obonode/obojobo-chunks-heading/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-heading", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Heading content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-html/package.json b/packages/obonode/obojobo-chunks-html/package.json index 747d57963..070ee5a9b 100644 --- a/packages/obonode/obojobo-chunks-html/package.json +++ b/packages/obonode/obojobo-chunks-html/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-html", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "HTML content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-iframe/package.json b/packages/obonode/obojobo-chunks-iframe/package.json index 9eb421187..bcc075231 100644 --- a/packages/obonode/obojobo-chunks-iframe/package.json +++ b/packages/obonode/obojobo-chunks-iframe/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-iframe", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "IFrame content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-list/package.json b/packages/obonode/obojobo-chunks-list/package.json index 22928ca54..4b4f7b9db 100644 --- a/packages/obonode/obojobo-chunks-list/package.json +++ b/packages/obonode/obojobo-chunks-list/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-list", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "List content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-materia/package.json b/packages/obonode/obojobo-chunks-materia/package.json index d2f8c9c62..2ed023a90 100644 --- a/packages/obonode/obojobo-chunks-materia/package.json +++ b/packages/obonode/obojobo-chunks-materia/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-materia", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Materia content chunk for Obojobo", "scripts": { @@ -35,9 +35,9 @@ "lint-staged": "^10.5.4" }, "peerDependencies": { - "obojobo-chunks-iframe": "^16.0.0-alpha.0", - "obojobo-document-engine": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-chunks-iframe": "^16.0.0", + "obojobo-document-engine": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-math-equation/package.json b/packages/obonode/obojobo-chunks-math-equation/package.json index ac31820c1..5441f1d8e 100644 --- a/packages/obonode/obojobo-chunks-math-equation/package.json +++ b/packages/obonode/obojobo-chunks-math-equation/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-math-equation", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "MathEquation content chunk for Obojobo", "scripts": { @@ -30,7 +30,7 @@ "katex": "^0.13.1" }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-multiple-choice-assessment/package.json b/packages/obonode/obojobo-chunks-multiple-choice-assessment/package.json index b12d52f9d..7c226c20c 100644 --- a/packages/obonode/obojobo-chunks-multiple-choice-assessment/package.json +++ b/packages/obonode/obojobo-chunks-multiple-choice-assessment/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-multiple-choice-assessment", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "MCAssessment chunk for Obojobo", "scripts": { @@ -27,8 +27,8 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-chunks-question": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-chunks-question": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-numeric-assessment/package.json b/packages/obonode/obojobo-chunks-numeric-assessment/package.json index 0a3972dd0..d85fff201 100644 --- a/packages/obonode/obojobo-chunks-numeric-assessment/package.json +++ b/packages/obonode/obojobo-chunks-numeric-assessment/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-numeric-assessment", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "NumericAssessment chunk for Obojobo", "scripts": { @@ -30,8 +30,8 @@ "big.js": "^6.1.1" }, "peerDependencies": { - "obojobo-chunks-question": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-chunks-question": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-question-bank/package.json b/packages/obonode/obojobo-chunks-question-bank/package.json index d858f4b69..aca8aed5e 100644 --- a/packages/obonode/obojobo-chunks-question-bank/package.json +++ b/packages/obonode/obojobo-chunks-question-bank/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-question-bank", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "QuestionBank chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-question/package.json b/packages/obonode/obojobo-chunks-question/package.json index da3ebda29..5fb7edfbc 100644 --- a/packages/obonode/obojobo-chunks-question/package.json +++ b/packages/obonode/obojobo-chunks-question/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-question", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Question content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-table/editor-registration.js b/packages/obonode/obojobo-chunks-table/editor-registration.js index c3defba7f..682b7bae8 100644 --- a/packages/obonode/obojobo-chunks-table/editor-registration.js +++ b/packages/obonode/obojobo-chunks-table/editor-registration.js @@ -41,9 +41,23 @@ const plugins = { // Editable Plugins - These are used by the PageEditor component to augment React functions // They affect individual nodes independently of one another onKeyDown(entry, editor, event) { + const computeModifiedPath = (node, row, col) => { + // eslint-disable-next-line prefer-const + let newPath = [...editor.selection.anchor.path] + newPath[newPath.length - 4] = node + newPath[newPath.length - 3] = row + newPath[newPath.length - 2] = col + return newPath + } // Calculate next path based on direction given const calculateNextPath = direction => { - const [node, row, col] = editor.selection.anchor.path + const currentPath = editor.selection.anchor.path + if (currentPath.length < 4) { + return currentPath + } + const col = currentPath[currentPath.length - 2] + const row = currentPath[currentPath.length - 3] + const node = currentPath[currentPath.length - 4] const numCols = editor.children[node].content.numCols @@ -51,63 +65,51 @@ const plugins = { switch (direction) { case 'down': - nextPath = [node, row + 1, col] + nextPath = computeModifiedPath(node, row + 1, col) break case 'right': - nextPath = [node, row, col + 1] + nextPath = computeModifiedPath(node, row, col + 1) break case 'up': - nextPath = [node, row - 1, col] + nextPath = computeModifiedPath(node, row - 1, col) break case 'left': - nextPath = [node, row, col - 1] + nextPath = computeModifiedPath(node, row, col - 1) break } // If next path is valid, jump to it if (Node.has(editor, nextPath)) { return nextPath - } else if (direction === 'right' && Node.has(editor, [node, row + 1, 0])) { + } else if (direction === 'right' && Node.has(editor, computeModifiedPath(node, row + 1, 0))) { // If moving right but already at rightmost cell, move to beginning of the row below - return [node, row + 1, 0] - } else if (direction === 'left' && Node.has(editor, [node, row - 1, numCols - 1])) { + return computeModifiedPath(node, row + 1, 0) + } else if ( + direction === 'left' && + Node.has(editor, computeModifiedPath(node, row - 1, numCols - 1)) + ) { // If moving left but already at leftmost cell, move to end of the row above - return [node, row - 1, numCols - 1] - } else if (direction === 'up' && Node.has(editor, [node - 1])) { - // Move to node above table - return [node - 1] - } else if (direction === 'down' && Node.has(editor, [node + 1])) { - // Move to node below table - return [node + 1] + return computeModifiedPath(node, row - 1, numCols - 1) } - - // If no adjacent paths, return current path - return editor.selection.anchor.path + // If no valid paths, fail gracefully + return false } // Move editor selection based on direction given const moveCursor = direction => { - const currentPath = editor.selection.anchor.path const nextPath = calculateNextPath(direction) - - const isExitingTable = nextPath[0] !== currentPath[0] - - if (nextPath !== currentPath) { - const focus = Editor.start(editor, nextPath) - let anchor - - // If exiting table, do not select entire content of new node - if (isExitingTable) { - anchor = focus - } else { - anchor = Editor.end(editor, nextPath) - } - - Transforms.setSelection(editor, { - focus, - anchor - }) + if (!nextPath) { + event.referredFromTable = true + return } + + const focus = Editor.start(editor, nextPath) + const anchor = Editor.end(editor, nextPath) + Transforms.setSelection(editor, { + focus, + anchor + }) + event.preventDefault() } switch (event.key) { @@ -117,7 +119,6 @@ const plugins = { case 'Enter': case 'ArrowDown': - event.preventDefault() moveCursor('down') break @@ -125,8 +126,6 @@ const plugins = { // If shift isn't pressed and editing text, allow tab navigation to dropdown menu if (!event.shiftKey && Range.isCollapsed(editor.selection)) break - event.preventDefault() - // Handle Shift+Tab left navigation if (event.shiftKey) { moveCursor('left') @@ -142,7 +141,6 @@ const plugins = { // If pressing Ctrl or Command, deselect text if (event.metaKey || event.ctrlKey) break - event.preventDefault() moveCursor('right') break @@ -153,12 +151,10 @@ const plugins = { // If pressing Ctrl or Command, deselect text if (event.metaKey || event.ctrlKey) break - event.preventDefault() moveCursor('left') break case 'ArrowUp': - event.preventDefault() moveCursor('up') break } diff --git a/packages/obonode/obojobo-chunks-table/editor-registration.test.js b/packages/obonode/obojobo-chunks-table/editor-registration.test.js index 87007c656..18bdb114a 100644 --- a/packages/obonode/obojobo-chunks-table/editor-registration.test.js +++ b/packages/obonode/obojobo-chunks-table/editor-registration.test.js @@ -173,8 +173,8 @@ describe('Table editor', () => { test('plugins.onKeyDown deals with [Enter]', () => { editor.selection = { - anchor: { path: [1, 0, 0], offset: 1 }, - focus: { path: [1, 0, 0], offset: 3 } + anchor: { path: [1, 0, 0, 0], offset: 1 }, + focus: { path: [1, 0, 0, 0], offset: 3 } } const event = { @@ -189,8 +189,8 @@ describe('Table editor', () => { test('plugins.onKeyDown deals with [ArrowDown]', () => { editor.selection = { - anchor: { path: [1, 0, 0], offset: 1 }, - focus: { path: [1, 0, 0], offset: 3 } + anchor: { path: [1, 0, 0, 0], offset: 1 }, + focus: { path: [1, 0, 0, 0], offset: 3 } } const event = { @@ -205,8 +205,8 @@ describe('Table editor', () => { test('plugins.onKeyDown deals with [ArrowUp]', () => { editor.selection = { - anchor: { path: [1, 1, 0], offset: 1 }, - focus: { path: [1, 1, 0], offset: 3 } + anchor: { path: [1, 1, 0, 0], offset: 1 }, + focus: { path: [1, 1, 0, 0], offset: 3 } } const event = { @@ -408,8 +408,7 @@ describe('Table editor', () => { } Table.plugins.onKeyDown([editor.children[1], [0]], editor, event) - expect(event.preventDefault).toHaveBeenCalled() - expect(editor.selection.anchor.path).toEqual([1, 0, 0, 0]) + expect(event.preventDefault).not.toHaveBeenCalled() }) test('plugins.onKeyDown deals with [ArrowUp] to content above table', () => { @@ -424,8 +423,7 @@ describe('Table editor', () => { } Table.plugins.onKeyDown([editor.children[1], [0]], editor, event) - expect(event.preventDefault).toHaveBeenCalled() - expect(editor.selection.anchor.path).toEqual([0, 0, 0]) + expect(event.preventDefault).not.toHaveBeenCalled() }) test('plugins.onKeyDown deals with [ArrowDown] to content below table', () => { @@ -439,9 +437,23 @@ describe('Table editor', () => { preventDefault: jest.fn() } + Table.plugins.onKeyDown([editor.children[1], [0]], editor, event) + expect(event.preventDefault).not.toHaveBeenCalled() + }) + + test('plugins.onKeyDown reverts to default when invalid paths are used', () => { + editor.selection = { + anchor: { path: [1, 1, 0], offset: 2 }, + focus: { path: [1, 1, 0], offset: 4 } + } + + const event = { + key: 'ArrowDown', + preventDefault: jest.fn() + } + Table.plugins.onKeyDown([editor.children[1], [0]], editor, event) expect(event.preventDefault).toHaveBeenCalled() - expect(editor.selection.anchor.path).toEqual([2, 0, 0]) }) test('plugins.onKeyDown deals with [Backspace]', () => { diff --git a/packages/obonode/obojobo-chunks-table/package.json b/packages/obonode/obojobo-chunks-table/package.json index dcc77f12d..a5fe84acc 100644 --- a/packages/obonode/obojobo-chunks-table/package.json +++ b/packages/obonode/obojobo-chunks-table/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-table", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Table content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-text/package.json b/packages/obonode/obojobo-chunks-text/package.json index e571bade9..0fdf3ed0c 100644 --- a/packages/obonode/obojobo-chunks-text/package.json +++ b/packages/obonode/obojobo-chunks-text/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-text", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Text content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-chunks-youtube/package.json b/packages/obonode/obojobo-chunks-youtube/package.json index 33b982a77..165c7c863 100644 --- a/packages/obonode/obojobo-chunks-youtube/package.json +++ b/packages/obonode/obojobo-chunks-youtube/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-chunks-youtube", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Youtube content chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-modules-module/package.json b/packages/obonode/obojobo-modules-module/package.json index f4e4da0db..9a657925c 100644 --- a/packages/obonode/obojobo-modules-module/package.json +++ b/packages/obonode/obojobo-modules-module/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-modules-module", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Default Module node for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-pages-page/package.json b/packages/obonode/obojobo-pages-page/package.json index b821249c9..4649a7601 100644 --- a/packages/obonode/obojobo-pages-page/package.json +++ b/packages/obonode/obojobo-pages-page/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-pages-page", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Page chunk for Obojobo", "scripts": { @@ -27,8 +27,8 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-document-engine": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-document-engine": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-sections-assessment/package.json b/packages/obonode/obojobo-sections-assessment/package.json index d0e919697..6d9d61282 100644 --- a/packages/obonode/obojobo-sections-assessment/package.json +++ b/packages/obonode/obojobo-sections-assessment/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-sections-assessment", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Assessment section for Obojobo", "scripts": { @@ -27,8 +27,8 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-document-engine": "^16.0.0-alpha.0", - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-document-engine": "^16.0.0", + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/obonode/obojobo-sections-content/package.json b/packages/obonode/obojobo-sections-content/package.json index bfed2c9e6..d2f511c69 100644 --- a/packages/obonode/obojobo-sections-content/package.json +++ b/packages/obonode/obojobo-sections-content/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-sections-content", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Content section chunk for Obojobo", "scripts": { @@ -27,7 +27,7 @@ "singleQuote": true }, "peerDependencies": { - "obojobo-lib-utils": "^16.0.0-alpha.0" + "obojobo-lib-utils": "^16.0.0" }, "jest": { "testMatch": [ diff --git a/packages/util/eslint-config-obojobo/package.json b/packages/util/eslint-config-obojobo/package.json index f5a1dbb30..b2249827b 100644 --- a/packages/util/eslint-config-obojobo/package.json +++ b/packages/util/eslint-config-obojobo/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-obojobo", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "scripts": { "lint": "echo 'not implemented'", diff --git a/packages/util/obojobo-lib-utils/package.json b/packages/util/obojobo-lib-utils/package.json index 5bd1336f5..072f887a7 100644 --- a/packages/util/obojobo-lib-utils/package.json +++ b/packages/util/obojobo-lib-utils/package.json @@ -1,6 +1,6 @@ { "name": "obojobo-lib-utils", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "description": "Assortment of reusable parts for obojobo libraries.", "scripts": { diff --git a/packages/util/stylelint-config-obojobo/package.json b/packages/util/stylelint-config-obojobo/package.json index 6161a6e63..e70ac7648 100644 --- a/packages/util/stylelint-config-obojobo/package.json +++ b/packages/util/stylelint-config-obojobo/package.json @@ -1,6 +1,6 @@ { "name": "stylelint-config-obojobo", - "version": "16.0.0-alpha.0", + "version": "16.0.0", "license": "AGPL-3.0-only", "scripts": { "lint": "echo 'not implemented'",