Skip to content
Snippets Groups Projects
Commit e1e039f2 authored by Jack Reed's avatar Jack Reed
Browse files

Enable basic editing of annotations

parent a1bf5267
Branches
No related tags found
No related merge requests found
......@@ -31,6 +31,11 @@ class AnnotationCreation extends Component {
/** */
constructor(props) {
super(props);
const annoState = {};
if (props.annotation) {
annoState.annoBody = props.annotation.body.value;
annoState.svg = props.annotation.target.selector.value;
}
this.state = {
activeTool: 'cursor',
annoBody: '',
......@@ -44,6 +49,7 @@ class AnnotationCreation extends Component {
strokeWidth: 1,
svg: null,
xywh: null,
...annoState,
};
this.submitForm = this.submitForm.bind(this);
......@@ -113,7 +119,7 @@ class AnnotationCreation extends Component {
submitForm(e) {
e.preventDefault();
const {
canvases, parentactions, receiveAnnotation, config,
annotation, canvases, parentactions, receiveAnnotation, config,
} = this.props;
const { annoBody, xywh, svg } = this.state;
canvases.forEach((canvas) => {
......@@ -121,11 +127,16 @@ class AnnotationCreation extends Component {
const anno = new WebAnnotation({
body: annoBody,
canvasId: canvas.id,
id: `https://example.org/iiif/book1/page/manifest/${uuid()}`,
id: (annotation && annotation.id) || `https://example.org/iiif/book1/page/manifest/${uuid()}`,
svg,
xywh,
}).toJson();
const newAnnoPage = localStorageAdapter.create(anno);
let newAnnoPage;
if (annotation) {
newAnnoPage = localStorageAdapter.update(anno);
} else {
newAnnoPage = localStorageAdapter.create(anno);
}
receiveAnnotation(canvas.id, localStorageAdapter.annotationPageId, newAnnoPage);
});
this.setState({
......@@ -158,7 +169,7 @@ class AnnotationCreation extends Component {
const { classes, parentactions, windowId } = this.props;
const {
activeTool, colorPopoverOpen, currentColorType, fillColor, popoverAnchorEl, strokeColor,
popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth,
popoverLineWeightAnchorEl, lineWeightPopoverOpen, strokeWidth, annoBody, svg,
} = this.state;
return (
<Paper className={classes.root}>
......@@ -167,6 +178,7 @@ class AnnotationCreation extends Component {
fillColor={fillColor}
strokeColor={strokeColor}
strokeWidth={strokeWidth}
svg={svg}
updateGeometry={this.updateGeometry}
windowId={windowId}
/>
......@@ -259,6 +271,7 @@ class AnnotationCreation extends Component {
</Grid>
<Grid item xs={12}>
<TextEditor
annoHtml={annoBody}
updateAnnotationBody={this.updateBody}
/>
</Grid>
......@@ -331,6 +344,7 @@ const styles = (theme) => ({
});
AnnotationCreation.propTypes = {
annotation: PropTypes.object, // eslint-disable-line react/forbid-prop-types
canvases: PropTypes.arrayOf(
PropTypes.shape({ id: PropTypes.string, index: PropTypes.number }),
),
......@@ -348,6 +362,7 @@ AnnotationCreation.propTypes = {
};
AnnotationCreation.defaultProps = {
annotation: null,
canvases: [],
parentactions: {},
};
......
......@@ -55,7 +55,7 @@ class AnnotationDrawing extends Component {
/** */
paperThing() {
const {
activeTool, fillColor, strokeColor, strokeWidth,
activeTool, fillColor, strokeColor, strokeWidth, svg,
} = this.props;
if (!activeTool || activeTool === 'cursor') return null;
// Setup Paper View to have the same center and zoom as the OSD Viewport
......@@ -95,7 +95,11 @@ class AnnotationDrawing extends Component {
canvasProps={{ style: { height: '100%', width: '100%' } }}
viewProps={viewProps}
>
{renderWithPaperScope((paper) => (
{renderWithPaperScope((paper) => {
if (svg) {
paper.project.importSVG(svg);
}
return (
<ActiveTool
onPathAdd={this.addPath}
pathProps={{
......@@ -104,7 +108,8 @@ class AnnotationDrawing extends Component {
strokeWidth: strokeWidth / paper.view.zoom,
}}
/>
))}
);
})}
</PaperContainer>
</div>
);
......@@ -125,6 +130,7 @@ AnnotationDrawing.propTypes = {
fillColor: PropTypes.string,
strokeColor: PropTypes.string,
strokeWidth: PropTypes.number,
svg: PropTypes.string,
updateGeometry: PropTypes.func.isRequired,
windowId: PropTypes.string.isRequired,
};
......@@ -134,6 +140,7 @@ AnnotationDrawing.defaultProps = {
fillColor: null,
strokeColor: '#00BFFF',
strokeWidth: 1,
svg: null,
};
......
......@@ -2,8 +2,10 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { MiradorMenuButton } from 'mirador/dist/es/src/components/MiradorMenuButton';
import DeleteIcon from '@material-ui/icons/Delete';
import EditIcon from '@material-ui/icons/Edit';
import flatten from 'lodash/flatten';
import AnnotationActionsContext from './AnnotationActionsContext';
import AnnotationCreation from './AnnotationCreation';
/** */
class CanvasListItem extends Component {
......@@ -12,6 +14,7 @@ class CanvasListItem extends Component {
super(props);
this.handleDelete = this.handleDelete.bind(this);
this.handleEdit = this.handleEdit.bind(this);
}
/** */
......@@ -25,6 +28,34 @@ class CanvasListItem extends Component {
});
}
/** */
handleEdit() {
const {
addCompanionWindow, canvases, config, receiveAnnotation, windowId,
} = this.context;
const { annotationid } = this.props;
let annotation;
canvases.some((canvas) => {
const localStorageAdapter = config.annotation.adapter(canvas.id);
annotation = localStorageAdapter.get(annotationid);
return (annotation);
});
console.log(annotation);
addCompanionWindow('custom', {
children: (
<AnnotationCreation
annotation={annotation}
canvases={canvases}
receiveAnnotation={receiveAnnotation}
config={config}
windowId={windowId}
/>
),
position: 'right',
title: 'Edit annotation',
});
}
/** */
editable() {
const { canvases, storageAdapter } = this.context;
......@@ -48,12 +79,20 @@ class CanvasListItem extends Component {
>
{children}
{this.editable() && (
<div>
<MiradorMenuButton
aria-label="Edit"
onClick={this.handleEdit}
>
<EditIcon />
</MiradorMenuButton>
<MiradorMenuButton
aria-label="Delete"
onClick={this.handleDelete}
>
<DeleteIcon />
</MiradorMenuButton>
</div>
)}
</li>
);
......@@ -66,6 +105,7 @@ CanvasListItem.propTypes = {
PropTypes.func,
PropTypes.node,
]).isRequired,
targetProps: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
};
CanvasListItem.contextType = AnnotationActionsContext;
......
......@@ -19,9 +19,16 @@ export default class LocalStorageAdapter {
}
/** */
// update(annoId) {
// // todo
// }
update(annotation) {
const annotationPage = this.all();
if (annotationPage) {
const currentIndex = annotationPage.items.findIndex((item) => item.id === annotation.id);
annotationPage.items.splice(currentIndex, 1, annotation);
localStorage.setItem(this.annotationPageId, JSON.stringify(annotationPage));
return annotationPage;
}
return null;
}
/** */
delete(annoId) {
......@@ -33,6 +40,15 @@ export default class LocalStorageAdapter {
return annotationPage;
}
/** */
get(annoId) {
const annotationPage = this.all();
if (annotationPage) {
return annotationPage.items.find((item) => item.id === annoId);
}
return null;
}
/** */
all() {
return JSON.parse(localStorage.getItem(this.annotationPageId));
......
......@@ -7,13 +7,16 @@ import BoldIcon from '@material-ui/icons/FormatBold';
import ItalicIcon from '@material-ui/icons/FormatItalic';
import { withStyles } from '@material-ui/core/styles';
import { stateToHTML } from 'draft-js-export-html';
import { stateFromHTML } from 'draft-js-import-html';
/** */
class TextEditor extends Component {
/** */
constructor(props) {
super(props);
this.state = { editorState: EditorState.createEmpty() };
this.state = {
editorState: EditorState.createWithContent(stateFromHTML(props.annoHtml)),
};
this.onChange = this.onChange.bind(this);
this.handleKeyCommand = this.handleKeyCommand.bind(this);
this.handleFormating = this.handleFormating.bind(this);
......@@ -102,6 +105,7 @@ const styles = (theme) => ({
});
TextEditor.propTypes = {
annoHtml: PropTypes.string,
classes: PropTypes.shape({
editorRoot: PropTypes.string,
}).isRequired,
......@@ -109,6 +113,7 @@ TextEditor.propTypes = {
};
TextEditor.defaultProps = {
annoHtml: '',
updateAnnotationBody: () => {},
};
......
......@@ -10,7 +10,8 @@ class CanvasAnnotationsWrapper extends Component {
/** */
render() {
const {
canvases, config, receiveAnnotation, TargetComponent, targetProps,
addCompanionWindow, canvases, config, receiveAnnotation, TargetComponent,
targetProps,
} = this.props;
const props = {
...targetProps,
......@@ -19,9 +20,12 @@ class CanvasAnnotationsWrapper extends Component {
return (
<AnnotationActionsContext.Provider
value={{
addCompanionWindow,
canvases,
config,
receiveAnnotation,
storageAdapter: config.annotation.adapter,
windowId: targetProps.windowId,
}}
>
<TargetComponent
......@@ -33,6 +37,7 @@ class CanvasAnnotationsWrapper extends Component {
}
CanvasAnnotationsWrapper.propTypes = {
addCompanionWindow: PropTypes.func.isRequired,
canvases: PropTypes.arrayOf(
PropTypes.shape({ id: PropTypes.string, index: PropTypes.number }),
),
......@@ -63,6 +68,9 @@ function mapStateToProps(state, { targetProps }) {
/** */
const mapDispatchToProps = (dispatch, props) => ({
addCompanionWindow: (content, additionalProps) => dispatch(
actions.addCompanionWindow(props.targetProps.windowId, { content, ...additionalProps }),
),
receiveAnnotation: (targetId, id, annotation) => dispatch(
actions.receiveAnnotation(targetId, id, annotation),
),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment