Commit 21c0ffe3 authored by Christos's avatar Christos
Browse files

Merge branch 'caption-container' into 'master'

Caption container

See merge request wax/wax!253
parents ba1f9b9e b531f23f
......@@ -11,6 +11,7 @@ import {
last,
first,
findIndex,
maxBy,
} from 'lodash'
import { EventEmitter } from 'substance'
......@@ -80,9 +81,10 @@ class AbstractProvider extends EventEmitter {
container = containers[0]
}
const blockPosition = container.getPosition(blockId)
const blockPosition = this.setBlockPosition(container, blockId)
const nodePosition = node.start.offset
const depth = this.setNodeDepth(node)
const depth = this.setNodeDepth(node, container, blockId)
const containerOrder = container.order ? container.order : 0
return {
id: node.id,
......@@ -91,17 +93,61 @@ class AbstractProvider extends EventEmitter {
node,
containerId: container.id,
containerType: container.type,
order: container.order ? container.order : 0,
order: containerOrder,
depth,
}
})
return sortBy(currentNodes, [
'order',
return this.computeHash(
sortBy(currentNodes, ['order', 'blockPosition', 'depth', 'nodePosition']),
)
}
computeHash(nodes) {
if (nodes.length === 0) return []
const {
maxOrder,
maxBlockPosition,
maxDepth,
maxStartOffset,
} = this.computeMaxes(nodes)
forEach(nodes, (value, key) => {
nodes[key].hash = `${this.pad(value.order, maxOrder)}${this.pad(
value.blockPosition,
maxBlockPosition,
)}${this.pad(value.depth, maxDepth)}${this.pad(
value.node.start.offset,
maxStartOffset,
)}`
})
return nodes
}
computeMaxes(nodes) {
const maxBlockPosition = maxBy(
clone(nodes),
'blockPosition',
'depth',
'nodePosition',
])
).blockPosition.toString().length
const maxOrder = maxBy(clone(nodes), 'order').order.toString().length
const maxDepth = maxBy(clone(nodes), 'depth').depth.toString().length
const maxStartOffset = maxBy(
clone(nodes),
'node.start.offset',
).node.start.offset.toString().length
return {
maxOrder,
maxBlockPosition,
maxDepth,
maxStartOffset,
}
}
pad(num, size) {
var s = num + ''
while (s.length < size) s = '0' + s
return s
}
sortNodesBySurface() {
......@@ -129,111 +175,93 @@ class AbstractProvider extends EventEmitter {
const { editorSession } = this
const selection = editorSession.getSelection()
const container = this.getContainerForSelection(selection)
const selectionBlockPositon = container.getPosition(selection.path[0])
const depth = this.setNodeDepth(selection)
const selectionBlockPositon = this.setBlockPosition(
container,
selection.path[0],
)
const selectionDepth = this.setNodeDepth(selection, container)
const containerOrder = container.order ? container.order : 0
const matches = this.getEntries()
let found = ''
const {
maxOrder,
maxBlockPosition,
maxDepth,
maxStartOffset,
} = this.computeMaxes(matches)
const currentHash = `${this.pad(containerOrder, maxOrder)}${this.pad(
selectionBlockPositon,
maxBlockPosition,
)}${this.pad(selectionDepth, maxDepth)}${this.pad(
selection.start.offset,
maxStartOffset,
)}`
let found = undefined
forEach(matches, match => {
if (
match.containerId === container.id &&
match.blockPosition === selectionBlockPositon &&
match.depth === depth &&
match.node.start.offset > selection.start.offset
) {
if (currentHash < match.hash) {
found = match
return false
} else if (
match.containerId === container.id &&
match.depth > depth &&
match.blockPosition === selectionBlockPositon
) {
found = match
return false
} else if (
match.containerId === container.id &&
match.blockPosition > selectionBlockPositon
) {
found = match
return false
} else if (match.containerId !== container.id) {
const same = matches.filter(m => {
return m.containerId === container.id
})
if (isEmpty(same)) {
found = matches[0]
} else {
const index = matches.findIndex(
x =>
x.node.start === last(same).node.start &&
x.node.end === last(same).node.end,
)
found = matches[index + 1]
}
} else {
found = matches[0]
}
})
if (found) return found
return false
return first(matches)
}
getPreviousNode() {
const { editorSession } = this
const selection = editorSession.getSelection()
const container = this.getContainerForSelection(selection)
const selectionBlockPositon = container.getPosition(selection.path[0])
const depth = this.setNodeDepth(selection)
const selectionBlockPositon = this.setBlockPosition(
container,
selection.path[0],
)
const selectionDepth = this.setNodeDepth(selection, container)
const containerOrder = container.order ? container.order : 0
const matches = this.getEntries()
let found = ''
const {
maxOrder,
maxBlockPosition,
maxDepth,
maxStartOffset,
} = this.computeMaxes(matches)
const currentHash = `${this.pad(containerOrder, maxOrder)}${this.pad(
selectionBlockPositon,
maxBlockPosition,
)}${this.pad(selectionDepth, maxDepth)}${this.pad(
selection.start.offset,
maxStartOffset,
)}`
let found = undefined
eachRight(matches, match => {
if (
match.containerId === container.id &&
match.blockPosition === selectionBlockPositon &&
match.depth === depth &&
match.node.start.offset < selection.start.offset
) {
found = match
return false
} else if (
match.containerId === container.id &&
match.depth < depth &&
match.blockPosition === selectionBlockPositon
) {
found = match
return false
} else if (
match.containerId === container.id &&
match.blockPosition < selectionBlockPositon
) {
if (parseInt(currentHash) > parseInt(match.hash)) {
found = match
return false
} else if (match.containerId !== container.id) {
const same = matches.filter(m => {
return m.containerId === container.id
})
if (isEmpty(same)) {
found = last(matches)
} else {
const index = matches.findIndex(
x =>
x.node.start === first(same).node.start &&
x.node.end === first(same).node.end,
)
found = matches[index - 1]
}
} else {
found = last(matches)
}
})
if (found) return found
return false
return last(matches)
}
setNodeDepth(node) {
setBlockPosition(container, blockId) {
let blockPosition = container.getPosition(blockId)
if (container.id.includes('caption')) {
const mainSurface = this.getMainSurface()
blockPosition = mainSurface.getPosition(container.id.substring(8))
}
return blockPosition
}
setNodeDepth(node, container, blockId) {
let depth = 0
if (container.id.includes('caption')) {
depth = container.getPosition(node.path[0]) + 1
}
if (node.path[0].includes('list-item')) {
let list = this.document.get(node.path[0])
......@@ -285,6 +313,10 @@ class AbstractProvider extends EventEmitter {
getActiveSurface() {
return this.editorSession.surfaceManager.getFocusedSurface()
}
getMainSurface() {
return this.editorSession.document.get('main')
}
}
export default AbstractProvider
......@@ -13,6 +13,7 @@ class ContainerEditor extends SubstanceContainerEditor {
constructor(...props) {
super(...props)
this.context.editorSession.onUpdate('document', this.checkChange, this)
this.change = {}
this.focus = this.focus.bind(this)
this.spellchecker = false
......
......@@ -2,6 +2,53 @@ import { minBy, maxBy } from 'lodash'
import { AnnotationCommand } from 'substance'
class CommentCommand extends AnnotationCommand {
getCommandState(params, context) {
// const sel = params.selection
const sel = this._getSelection(params)
if (this.isDisabled(sel, params, context)) {
return {
disabled: true,
}
}
const annos = this._getAnnotationsForSelection(params)
const newState = {
disabled: false,
active: false,
mode: null,
}
const { surface } = params
if (surface.props.textCommands) {
if (
!['full', this.name].some(e => {
return surface.props.textCommands.indexOf(e) !== -1
})
) {
newState.disabled = true
return newState
}
}
if (this.canCreate(annos, sel)) {
newState.mode = 'create'
} else if (this.canFuse(annos, sel)) {
newState.mode = 'fuse'
} else if (this.canTruncate(annos, sel)) {
newState.active = true
newState.mode = 'truncate'
} else if (this.canExpand(annos, sel)) {
newState.mode = 'expand'
} else if (this.canDelete(annos, sel)) {
newState.active = true
newState.mode = 'delete'
} else {
newState.disabled = true
}
newState.showInContext = this.showInContext(sel, params, context)
return newState
}
// Override function to allow overlapping comments
canCreate(annos, sel, params) {
if (!sel.isCollapsed()) {
......
......@@ -7,6 +7,7 @@ class HighLighterCommand extends Command {
disabled: false,
}
const { surface } = params
const selection = params.editorSession.getSelection()
const highlightings = documentHelpers.getPropertyAnnotationsForSelection(
params.editorSession.getDocument(),
......@@ -14,6 +15,18 @@ class HighLighterCommand extends Command {
{ type: 'highlighter' },
)
if (surface && surface.props.textCommands) {
if (
!['full', this.name].some(e => {
return surface.props.textCommands.indexOf(e) !== -1
}) ||
surface.props.editing === 'selection'
) {
newState.disabled = true
return newState
}
}
if (
(selection.isCollapsed() && highlightings.length === 0) ||
!selection.isPropertySelection()
......
import { AnnotationCommand } from 'substance'
import WaxAnnotationCommand from '../../../commands/WaxAnnotationCommand'
class LinkCommand extends AnnotationCommand {
class LinkCommand extends WaxAnnotationCommand {
canFuse() {
return false
}
......
......@@ -590,8 +590,11 @@ class TrackChangesProvider extends AbstractProvider {
insertFirstDeletedCharacter(options) {
const { user, selection, surface, status, move } = options
let newSel = ''
const containerId = surface.containerId
const containerId = selection.containerId
let surfaceId = containerId
if (containerId.includes('caption')) {
surfaceId = `main/${containerId.substring(8)}/${containerId}`
}
const pointerStart =
move === 'left' ? selection.start.offset - 1 : selection.start.offset
......@@ -608,7 +611,7 @@ class TrackChangesProvider extends AbstractProvider {
tx.setSelection({
type: 'property',
containerId,
surfaceId: containerId,
surfaceId,
path: selection.path,
startOffset: pointerStart,
endOffset: pointerEnd,
......@@ -618,7 +621,7 @@ class TrackChangesProvider extends AbstractProvider {
status,
type: 'track-change',
containerId,
surfaceId: containerId,
surfaceId,
path: selection.path,
startOffset: pointerStart,
endOffset: pointerEnd,
......@@ -631,7 +634,7 @@ class TrackChangesProvider extends AbstractProvider {
tx.setSelection({
type: 'property',
containerId,
surfaceId: containerId,
surfaceId,
path: selection.path,
startOffset: createSelectionPointerStart,
endOffset: createSelectionPointerEnd,
......@@ -643,7 +646,11 @@ class TrackChangesProvider extends AbstractProvider {
expandDeleteAnnotation(options, annotation) {
const { selection, surface, move } = options
const containerId = surface.containerId
const containerId = selection.containerId
let surfaceId = containerId
if (containerId.includes('caption')) {
surfaceId = `main/${containerId.substring(8)}/${containerId}`
}
let sel = ''
const pointer =
......@@ -653,7 +660,7 @@ class TrackChangesProvider extends AbstractProvider {
sel = tx.createSelection({
type: 'property',
containerId,
surfaceId: containerId,
surfaceId,
path: selection.path,
startOffset: pointer,
endOffset: pointer,
......@@ -1359,7 +1366,12 @@ class TrackChangesProvider extends AbstractProvider {
resolve(annotations, action) {
const surface = this.getActiveSurface()
const containerId = surface.containerId
const { containerId } = surface
let surfaceId = containerId
if (containerId.includes('caption')) {
surfaceId = `main/${containerId.substring(8)}/${containerId}`
}
const toBeRemoved = []
const keepAnnotatios = []
const formatAdded = []
......@@ -1386,7 +1398,7 @@ class TrackChangesProvider extends AbstractProvider {
tx.create({
type: annotation.oldType[0].type,
containerId,
surfaceId: containerId,
surfaceId,
path: annotation.path,
start: annotation.start,
end: annotation.end,
......@@ -1417,7 +1429,7 @@ class TrackChangesProvider extends AbstractProvider {
type: 'property',
path: anno.path,
containerId,
surfaceId: containerId,
surfaceId,
startOffset: anno.start.offset,
endOffset: anno.end.offset,
})
......@@ -1426,7 +1438,7 @@ class TrackChangesProvider extends AbstractProvider {
})
// update ui for comments
const editor = this.config.controller
editor.emit('ui:updated')
// editor.emit('ui:updated')
// Update editor in note exists
if (this.rerenderEditor) {
......@@ -1451,12 +1463,16 @@ OTHER STUFF
focus(annotation) {
if (!annotation) return
const { containerId } = annotation
let surfaceId = containerId
if (containerId.includes('caption')) {
surfaceId = `main/${containerId.substring(8)}/${containerId}`
}
this.editorSession.transaction(tx => {
tx.setSelection({
type: 'property',
containerId: annotation.containerId,
surfaceId: annotation.containerId,
containerId,
surfaceId,
path: annotation.node.path,
startOffset: annotation.node.start.offset,
endOffset: annotation.node.start.offset,
......
......@@ -31,7 +31,6 @@ const createAdditionAnnotationOnLastChar = options => {
const deleteAllOwnAdditions = options => {
const { selection, surface } = options
const originalSelection = selection
// const originalSelection = selection || this.getSelection()
let shortenBy = 0
const additions = getAllAnnotationsByStatus(options, 'add')
......@@ -57,8 +56,6 @@ const deleteAllOwnAdditions = options => {
deleteSelection(options)
})
// throw klfjdskljfsj
return shortenBy // return how much shorter the selection should now be
}
......@@ -104,7 +101,6 @@ const selectCharacterAndMarkDeleted = options => {
export {
createAdditionAnnotationOnLastChar,
deleteAllOwnAdditions,
// deleteOrMergeAllOwnDeletions,
insertCharacterWithoutExpandingAnnotation,
selectCharacterAndMarkDeleted,
}
......@@ -3,7 +3,6 @@ const getSelection = surface => {
}
const isSelectionCollapsed = options => {
// const selection = this.getSelection()
const { selection } = options
const isCollapsed = selection.isCollapsed()
return isCollapsed
......@@ -11,26 +10,16 @@ const isSelectionCollapsed = options => {
// TODO -- refactor this and isAnnotationContainedWithinSelection into one
const isSelectionContainedWithin = (options, annotation, strict) => {
// const selection = this.getSelection()
const selection = getSelection(options.surface)
const annotationSelection = annotation.getSelection()
return annotationSelection.contains(selection, strict)
// const leftSide = (selection.startOffset < annotation.startOffset)
// const rightSide = (selection.endOffset > annotation.endOffset)
//
// if (leftSide || rightSide) return false
// return true
}
const moveCursorTo = (options, point) => {
// const selection = sel || this.getSelection()
// const { selection, surface } = options
const { surface } = options
const selection = getSelection(surface)
// const surface = this.getSurface()
// TODO -- use substance's selection.collapse(direction)
if (point === 'start') {
......@@ -45,7 +34,6 @@ const moveCursorTo = (options, point) => {
surface.editorSession.setSelection(selection)
}
// const setSelectionPlusOne = (direction) {
const setSelectionPlusOne = (options, direction) => {
const { selection, surface } = options
......
......@@ -7,7 +7,6 @@ import { annotationHelpers } from 'substance'
*/
const deleteCharacter = options => {
// const surface = this.getSurface()
const { direction, surface } = options
const move = direction.move
const info = { action: 'delete' }
......
......@@ -10,6 +10,7 @@ class FindAndReplaceModal extends Modal {
super(...props)
this.findInText = this.findInText.bind(this)
this.enterSearch = this.enterSearch.bind(this)
this.searchStringLength = 0
}
render($$) {
......@@ -121,7 +122,12 @@ class FindAndReplaceModal extends Modal {
}
matches = provider.excludeTrackChanges(matches, doc)
if (matches.length === this.state.matches.length) return