mirador-annotation-editor-video 1.0.99 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -35
- package/demo/src/index.js +8 -1
- package/es/IIIFUtils.js +3 -2
- package/es/TextEditor.js +7 -14
- package/es/annotationForm/AnnotationFormBody.js +1 -1
- package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +3 -2
- package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +1 -1
- package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Rectangle.js +1 -0
- package/es/annotationForm/AnnotationFormUtils.js +12 -18
- package/es/annotationForm/MultipleBodyTemplate.js +6 -5
- package/es/annotationForm/TargetSpatialInput.js +1 -1
- package/es/annotationForm/TextCommentInput.js +71 -0
- package/es/locales/locales_en.js +1 -0
- package/es/locales/locales_fr.js +1 -0
- package/package.json +2 -2
- package/src/IIIFUtils.js +7 -3
- package/src/TextEditor.js +7 -12
- package/src/annotationForm/AnnotationFormBody.js +1 -1
- package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +3 -1
- package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +1 -1
- package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Rectangle.js +1 -0
- package/src/annotationForm/AnnotationFormUtils.js +9 -13
- package/src/annotationForm/MultiTagsInput.js +0 -5
- package/src/annotationForm/MultipleBodyTemplate.js +6 -5
- package/src/annotationForm/TargetSpatialInput.js +2 -2
- package/src/annotationForm/TextCommentInput.js +72 -0
- package/src/locales/locales_en.js +1 -0
- package/src/locales/locales_fr.js +1 -0
package/README.md
CHANGED
|
@@ -4,57 +4,54 @@
|
|
|
4
4
|
|
|
5
5
|
### Generalities
|
|
6
6
|
|
|
7
|
-
`mirador-annotation-editor-video`(also known as "MAEV") is a [Mirador 4](https://github.com/projectmirador/mirador)
|
|
7
|
+
`mirador-annotation-editor-video`(also known as "MAEV") is a [Mirador 4](https://github.com/projectmirador/mirador)
|
|
8
|
+
plugin that
|
|
8
9
|
adds annotation creation tools to the user interface. It support both image and video annotation.
|
|
9
10
|
|
|
10
11
|
### Copyrights
|
|
11
12
|
|
|
13
|
+
Originally forked from https://github.com/ARVEST-APP/mirador-annotation-editor-video
|
|
14
|
+
|
|
12
15
|
#### Licence
|
|
13
16
|
|
|
14
17
|
This plugin is released under the **GPL v3** license unlike MAE and the original plugin.
|
|
15
18
|
|
|
16
|
-
Please acknowledge that any modification you make must be distributed under a compatible licence and cannot be closed
|
|
19
|
+
Please acknowledge that any modification you make must be distributed under a compatible licence and cannot be closed
|
|
17
20
|
source.
|
|
18
21
|
|
|
19
|
-
If you need to integrate this code base in closed source pieces of software, please contact us, so we can discuss dual
|
|
20
|
-
licencing.
|
|
21
|
-
|
|
22
|
-
#### Property
|
|
23
|
-
|
|
24
|
-
The base of this software (up to V1) is the property of [SATT Ouest Valorisation](https://www.ouest-valorisation.fr/)
|
|
25
|
-
that funded its development under the French public contract AO-MA2023-0004-DV5189.
|
|
22
|
+
If you need to integrate this code base in closed source pieces of software, please contact us, so we can discuss dual
|
|
23
|
+
licencing.
|
|
26
24
|
|
|
27
|
-
#### Authors
|
|
25
|
+
#### Authors
|
|
28
26
|
|
|
29
27
|
The authors of this software are :
|
|
30
28
|
|
|
31
29
|
- Clarisse Bardiot (concept and use cases)
|
|
32
30
|
- Jacob Hart (specifications)
|
|
33
31
|
- [Tétras Libre SARL](https://tetras-libre.fr) (development):
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
- David Rouquet
|
|
33
|
+
- Anthony Geourjon
|
|
34
|
+
- Antoine Roy
|
|
37
35
|
|
|
38
36
|
#### Contributors (updated february 2024)
|
|
39
37
|
|
|
40
|
-
- AZOPSOFT SAS
|
|
41
|
-
|
|
42
|
-
- Loïs Poujade (especially the original modifications to annotate videos)
|
|
38
|
+
- AZOPSOFT SAS
|
|
39
|
+
- Samuel Jugnet (especially code for the Konvas part)
|
|
43
40
|
|
|
44
|
-
### General functionalities
|
|
41
|
+
### General functionalities
|
|
45
42
|
|
|
46
|
-
- Activate a panel with tools to create annotations on IIIF documents (manifests) containing images **and videos with
|
|
47
|
-
MAEV**
|
|
43
|
+
- Activate a panel with tools to create annotations on IIIF documents (manifests) containing images **and videos with
|
|
44
|
+
MAEV**
|
|
48
45
|
- Spatial and temporal targets for annotations
|
|
49
46
|
- Overlay annotations (geometric forms, free hand drawing, text and images)
|
|
50
47
|
- Textual/semantic annotations and tags
|
|
51
48
|
- Annotation metadata (based on Dublin Core)
|
|
52
49
|
- Annotation with another manifest -> network of IIIF documents
|
|
53
50
|
|
|
54
|
-
### Technical aspects
|
|
51
|
+
### Technical aspects
|
|
55
52
|
|
|
56
53
|
- Update to Material UI 5 and React 18 to follow latest Mirador upgrades (We support mirador": "4.0.0-alpha.2",
|
|
57
|
-
- The [paperjs](http://paperjs.org/ ) library has been replaced with [Konvas](https://konvajs.org)
|
|
54
|
+
- The [paperjs](http://paperjs.org/ ) library has been replaced with [Konvas](https://konvajs.org)
|
|
58
55
|
- Major refactoring since the original `[mirador-annotations](https://github.com/ProjectMirador/mirador-annotations/)
|
|
59
56
|
plugins`
|
|
60
57
|
- Works with the original [Mirador 4](https://github.com/projectmirador/mirador) if you need only image annotation
|
|
@@ -70,18 +67,22 @@ npm install mirador-annotation-editor
|
|
|
70
67
|
You can override existing annotation plugin with your own versions by using npm. We support React 18 and MUI 5.
|
|
71
68
|
|
|
72
69
|
Update your `package.json` file to include the following dependencies and devDependencies:
|
|
70
|
+
|
|
73
71
|
```js
|
|
74
|
-
"mirador-annotations"
|
|
72
|
+
"mirador-annotations"
|
|
73
|
+
:
|
|
74
|
+
"npm:mirador-annotation-editor-video@^1.0.10",
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
You need also to use the custom version of Mirador 4.
|
|
78
78
|
|
|
79
79
|
```js
|
|
80
|
-
"mirador"
|
|
80
|
+
"mirador"
|
|
81
|
+
:
|
|
82
|
+
"npm@mirador-video@^1.0.17",
|
|
81
83
|
```
|
|
82
84
|
|
|
83
|
-
If you encounter this error :
|
|
84
|
-
|
|
85
|
+
If you encounter this error :
|
|
85
86
|
|
|
86
87
|
## Install (local)
|
|
87
88
|
|
|
@@ -101,23 +102,23 @@ npm start
|
|
|
101
102
|
```
|
|
102
103
|
|
|
103
104
|
## Use MAE with video annotation support
|
|
104
|
-
- If you need video annotation, you can use
|
|
105
|
-
[our fork of Mirador: mirador-video](https://github.com/SCENE-CE/mirador-video)
|
|
106
|
-
- In addition, we have developed a wrapper of MAE to support video annotation. This wrapper is called **MAEV** and is
|
|
107
|
-
available in the [mirador-annotation-editor-video](https://github.com/SCENE-CE/mirador-annotation-editor-video)
|
|
108
|
-
repository.
|
|
109
105
|
|
|
106
|
+
- If you need video annotation, you can use
|
|
107
|
+
[our fork of Mirador: mirador-video](https://github.com/SCENE-CE/mirador-video)
|
|
108
|
+
- In addition, we have developed a wrapper of MAE to support video annotation. This wrapper is called **MAEV** and is
|
|
109
|
+
available in the [mirador-annotation-editor-video](https://github.com/SCENE-CE/mirador-annotation-editor-video)
|
|
110
|
+
repository.
|
|
110
111
|
|
|
111
112
|
## Persisting Annotations
|
|
112
|
-
|
|
113
|
+
|
|
114
|
+
Persisting annotations requires implementing a IIIF annotation server. Several
|
|
113
115
|
[examples of annotation servers](https://github.com/IIIF/awesome-iiif#annotation-servers) are available on iiif-awesome.
|
|
114
116
|
|
|
115
|
-
`mirador-annotation-editor` currently supports adapters for
|
|
116
|
-
[annotot](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/AnnototAdapter.js) and
|
|
117
|
-
[local storage](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/LocalStorageAdapter.js). We
|
|
117
|
+
`mirador-annotation-editor` currently supports adapters for
|
|
118
|
+
[annotot](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/AnnototAdapter.js) and
|
|
119
|
+
[local storage](https://github.com/ProjectMirador/mirador-annotations/blob/master/src/LocalStorageAdapter.js). We
|
|
118
120
|
welcome contributions of adapters for other annotation servers.
|
|
119
121
|
|
|
120
|
-
|
|
121
122
|
## Contribute
|
|
122
123
|
|
|
123
124
|
Our plugin follow the Mirador guidelines. Development, design, and maintenance is driven by community needs and ongoing
|
package/demo/src/index.js
CHANGED
|
@@ -6,7 +6,14 @@ import { manifestsCatalog } from './manifestsCatalog';
|
|
|
6
6
|
const config = {
|
|
7
7
|
annotation: {
|
|
8
8
|
adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`, 'Anonymous User'),
|
|
9
|
-
|
|
9
|
+
commentTemplates: [{
|
|
10
|
+
title: 'Template',
|
|
11
|
+
content: '<h4>Comment</h4><p>comment content</p>',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
title: 'Template 2',
|
|
15
|
+
content: '<h4>Comment2</h4><p>comment content</p>',
|
|
16
|
+
}],
|
|
10
17
|
exportLocalStorageAnnotations: false, // display annotation JSON export button
|
|
11
18
|
tagsSuggestions: ['Mirador', 'Awesome', 'Viewer', 'IIIF'],
|
|
12
19
|
},
|
package/es/IIIFUtils.js
CHANGED
|
@@ -106,7 +106,7 @@ const getIIIFTargetFromMaeData = (maeData, canvasId, windowId = null, playerScal
|
|
|
106
106
|
case _AnnotationFormUtils.TEMPLATE.MULTIPLE_BODY_TYPE:
|
|
107
107
|
case _AnnotationFormUtils.TEMPLATE.TEXT_TYPE:
|
|
108
108
|
// In some case the target can be simplified in a string
|
|
109
|
-
if (maeTarget.drawingState.shapes
|
|
109
|
+
if (isSimpleTarget(maeTarget.drawingState.shapes)) {
|
|
110
110
|
return getIIIFTargetFromRectangleShape(maeTarget, canvasId, maeTarget.drawingState.shapes[0]);
|
|
111
111
|
}
|
|
112
112
|
// On the other case, the target is a SVG
|
|
@@ -119,6 +119,8 @@ const getIIIFTargetFromMaeData = (maeData, canvasId, windowId = null, playerScal
|
|
|
119
119
|
// Default return
|
|
120
120
|
return getIIIFTargetFullCanvas(maeData, canvasId);
|
|
121
121
|
};
|
|
122
|
+
exports.getIIIFTargetFromMaeData = getIIIFTargetFromMaeData;
|
|
123
|
+
const isSimpleTarget = shapes => shapes.length === 1 && shapes[0].type === _KonvaUtils.SHAPES_TOOL.RECTANGLE && shapes[0].strokeColor === _AnnotationFormUtils.TARGET_TOOL_STATE.strokeColor && shapes[0].fillColor === _AnnotationFormUtils.TARGET_TOOL_STATE.fillColor;
|
|
122
124
|
|
|
123
125
|
/**
|
|
124
126
|
* Get the IIIF target from a Konva annotation (Drawing template)
|
|
@@ -126,7 +128,6 @@ const getIIIFTargetFromMaeData = (maeData, canvasId, windowId = null, playerScal
|
|
|
126
128
|
* @param canvasId
|
|
127
129
|
* @returns {`${string}#${string}`}
|
|
128
130
|
*/
|
|
129
|
-
exports.getIIIFTargetFromMaeData = getIIIFTargetFromMaeData;
|
|
130
131
|
const getIIIFTargetFromKonvaType = (maeData, canvasId) => {
|
|
131
132
|
// Simplified target for Konva annotation
|
|
132
133
|
console.log('Implement target as string with Konva annotation');
|
package/es/TextEditor.js
CHANGED
|
@@ -4,14 +4,12 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
var _react =
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
8
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
9
|
var _reactQuill = _interopRequireDefault(require("react-quill"));
|
|
10
10
|
require("react-quill/dist/quill.snow.css");
|
|
11
11
|
var _styles = require("@mui/material/styles");
|
|
12
12
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
-
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
13
|
const StyledReactQuill = (0, _styles.styled)(_reactQuill.default)(({
|
|
16
14
|
theme
|
|
17
15
|
}) => ({
|
|
@@ -22,20 +20,15 @@ const StyledReactQuill = (0, _styles.styled)(_reactQuill.default)(({
|
|
|
22
20
|
|
|
23
21
|
/** Rich text editor for annotation body */
|
|
24
22
|
function TextEditor({
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
text,
|
|
24
|
+
setText
|
|
27
25
|
}) {
|
|
28
|
-
const [editorHtml, setEditorHtml] = (0, _react.useState)(annoHtml);
|
|
29
|
-
|
|
30
26
|
/**
|
|
31
27
|
* Handle Change On ReactQuil Editor
|
|
32
28
|
* @param html
|
|
33
29
|
*/
|
|
34
30
|
const handleChange = html => {
|
|
35
|
-
|
|
36
|
-
if (updateAnnotationBody) {
|
|
37
|
-
updateAnnotationBody(html);
|
|
38
|
-
}
|
|
31
|
+
setText(html);
|
|
39
32
|
};
|
|
40
33
|
const modules = {
|
|
41
34
|
toolbar: [[{
|
|
@@ -60,7 +53,7 @@ function TextEditor({
|
|
|
60
53
|
return /*#__PURE__*/_react.default.createElement("div", {
|
|
61
54
|
"data-text-editor": "name"
|
|
62
55
|
}, /*#__PURE__*/_react.default.createElement(StyledReactQuill, {
|
|
63
|
-
value:
|
|
56
|
+
value: text,
|
|
64
57
|
onChange: handleChange,
|
|
65
58
|
placeholder: "Your text here",
|
|
66
59
|
bounds: "[data-text-editor=\"name\"]",
|
|
@@ -69,7 +62,7 @@ function TextEditor({
|
|
|
69
62
|
}));
|
|
70
63
|
}
|
|
71
64
|
TextEditor.propTypes = {
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
setText: _propTypes.default.func.isRequired,
|
|
66
|
+
text: _propTypes.default.string.isRequired
|
|
74
67
|
};
|
|
75
68
|
var _default = exports.default = TextEditor;
|
|
@@ -88,7 +88,7 @@ function AnnotationFormBody({
|
|
|
88
88
|
saveAnnotation: saveAnnotation,
|
|
89
89
|
t: t,
|
|
90
90
|
windowId: windowId,
|
|
91
|
-
commentTemplate: config?.annotation?.
|
|
91
|
+
commentTemplate: config?.annotation?.commentTemplates ?? [],
|
|
92
92
|
tagsSuggestions: config?.annotation?.tagsSuggestions ?? []
|
|
93
93
|
})), debugMode && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.default, null, playerReferences.getMediaType()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('scale'), ":", playerReferences.getScale()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('zoom'), ":", playerReferences.getZoom()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('image_true_size'), ":", playerReferences.getMediaTrueWidth(), ' ', "x", playerReferences.getMediaTrueHeight()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('container_size'), ":", playerReferences.getContainerWidth(), ' ', "x", playerReferences.getContainerHeight()), /*#__PURE__*/_react.default.createElement(_Typography.default, null, t('image_displayed'), ":", playerReferences.getDisplayedMediaWidth(), ' ', "x", playerReferences.getDisplayedMediaHeight())));
|
|
94
94
|
}
|
|
@@ -55,7 +55,7 @@ function AnnotationFormOverlayTool({
|
|
|
55
55
|
activeTool: _KonvaUtils.SHAPES_TOOL.RECTANGLE
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
|
-
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, toolState.activeTool === _KonvaUtils.OVERLAY_TOOL.EDIT && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, currentShape && displayMode === _KonvaUtils.KONVA_MODE.DRAW && /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_Typography.default, {
|
|
58
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, toolState.activeTool === _KonvaUtils.OVERLAY_TOOL.EDIT && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, (currentShape && displayMode === _KonvaUtils.KONVA_MODE.DRAW || currentShape && displayMode === _KonvaUtils.KONVA_MODE.TARGET) && /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_Typography.default, {
|
|
59
59
|
variant: "subFormSectionTitle"
|
|
60
60
|
}, t('selected_object')), /*#__PURE__*/_react.default.createElement(_AnnotationFormOverlayToolOptions.default, {
|
|
61
61
|
t: t,
|
|
@@ -72,7 +72,8 @@ function AnnotationFormOverlayTool({
|
|
|
72
72
|
text: currentShape.text
|
|
73
73
|
},
|
|
74
74
|
setToolState: customUpdateToolState,
|
|
75
|
-
displayMode: displayMode
|
|
75
|
+
displayMode: displayMode,
|
|
76
|
+
currentShape: currentShape
|
|
76
77
|
})), displayMode === _KonvaUtils.KONVA_MODE.DRAW && shapes.length > 0 && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.default, {
|
|
77
78
|
variant: "subFormSectionTitle"
|
|
78
79
|
}, t('object_list')), /*#__PURE__*/_react.default.createElement(_ShapesList.default, {
|
|
@@ -136,7 +136,7 @@ function AnnotationFormOverlayToolOptions({
|
|
|
136
136
|
text
|
|
137
137
|
});
|
|
138
138
|
};
|
|
139
|
-
return /*#__PURE__*/_react.default.createElement("div", null, displayMode === _KonvaUtils.KONVA_MODE.DRAW && (0, _KonvaUtils.isShapesTool)(toolState.activeTool) && /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
139
|
+
return /*#__PURE__*/_react.default.createElement("div", null, (displayMode === _KonvaUtils.KONVA_MODE.DRAW || displayMode === _KonvaUtils.KONVA_MODE.TARGET) && (0, _KonvaUtils.isShapesTool)(toolState.activeTool) && /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
140
140
|
container: true
|
|
141
141
|
}, /*#__PURE__*/_react.default.createElement(_ColorPicker.default, {
|
|
142
142
|
currentColor: currentColor,
|
|
@@ -72,6 +72,7 @@ function Rectangle({
|
|
|
72
72
|
}
|
|
73
73
|
Rectangle.propTypes = {
|
|
74
74
|
activeTool: _propTypes.default.string.isRequired,
|
|
75
|
+
baseStrokeWidth: _propTypes.default.number.isRequired,
|
|
75
76
|
displayMode: _propTypes.default.string.isRequired,
|
|
76
77
|
handleDragEnd: _propTypes.default.func.isRequired,
|
|
77
78
|
handleDragStart: _propTypes.default.func.isRequired,
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.TEMPLATE_TYPES = exports.TEMPLATE = exports.TARGET_VIEW = exports.TAG_VIEW = exports.StyledToggleButtonGroup = exports.OVERLAY_VIEW = exports.MEDIA_TYPES = exports.MANIFEST_LINK_VIEW = exports.IMAGE_TOOL_STATE = exports.DEFAULT_TOOL_STATE = void 0;
|
|
7
|
-
exports.getTargetSVGToolState = getTargetSVGToolState;
|
|
8
|
-
exports.isValidUrl = exports.getTemplateType = void 0;
|
|
6
|
+
exports.isValidUrl = exports.getTemplateType = exports.TEMPLATE_TYPES = exports.TEMPLATE = exports.TARGET_VIEW = exports.TARGET_TOOL_STATE = exports.TAG_VIEW = exports.StyledToggleButtonGroup = exports.OVERLAY_VIEW = exports.MEDIA_TYPES = exports.MANIFEST_LINK_VIEW = exports.IMAGE_TOOL_STATE = exports.DEFAULT_TOOL_STATE = void 0;
|
|
9
7
|
exports.saveAnnotationInStorageAdapter = saveAnnotationInStorageAdapter;
|
|
10
8
|
exports.secondsToHMSarray = secondsToHMSarray;
|
|
11
9
|
var _TextFields = _interopRequireDefault(require("@mui/icons-material/TextFields"));
|
|
@@ -158,22 +156,18 @@ const IMAGE_TOOL_STATE = exports.IMAGE_TOOL_STATE = {
|
|
|
158
156
|
|
|
159
157
|
/**
|
|
160
158
|
* Specific Tool state for the target SVG
|
|
161
|
-
* @param imageZoom
|
|
162
|
-
* @returns {{activeTool: string, closedMode: string, image: {id: null}, imageEvent: null,
|
|
163
|
-
* strokeColor: string, strokeWidth: number}}
|
|
164
159
|
*/
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
160
|
+
const TARGET_TOOL_STATE = exports.TARGET_TOOL_STATE = {
|
|
161
|
+
activeTool: _KonvaUtils.OVERLAY_TOOL.SHAPE,
|
|
162
|
+
closedMode: 'closed',
|
|
163
|
+
fillColor: 'rgba(100,100,100, 0)',
|
|
164
|
+
image: {
|
|
165
|
+
id: null
|
|
166
|
+
},
|
|
167
|
+
imageEvent: null,
|
|
168
|
+
strokeColor: 'rgba(255,0, 0, 0.5)',
|
|
169
|
+
strokeWidth: 5
|
|
170
|
+
};
|
|
177
171
|
const TARGET_VIEW = exports.TARGET_VIEW = 'target';
|
|
178
172
|
const OVERLAY_VIEW = exports.OVERLAY_VIEW = 'layer';
|
|
179
173
|
const TAG_VIEW = exports.TAG_VIEW = 'tag';
|
|
@@ -11,8 +11,8 @@ var _AnnotationFormFooter = _interopRequireDefault(require("./AnnotationFormFoot
|
|
|
11
11
|
var _AnnotationFormUtils = require("./AnnotationFormUtils");
|
|
12
12
|
var _TargetFormSection = _interopRequireDefault(require("./TargetFormSection"));
|
|
13
13
|
var _KonvaUtils = require("./AnnotationFormOverlay/KonvaDrawing/KonvaUtils");
|
|
14
|
-
var _TextFormSection = _interopRequireDefault(require("./TextFormSection"));
|
|
15
14
|
var _MultiTagsInput = require("./MultiTagsInput");
|
|
15
|
+
var _TextCommentInput = require("./TextCommentInput");
|
|
16
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
17
17
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
18
18
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
@@ -39,7 +39,7 @@ function MultipleBodyTemplate({
|
|
|
39
39
|
textBody: {
|
|
40
40
|
purpose: 'describing',
|
|
41
41
|
type: 'TextualBody',
|
|
42
|
-
value:
|
|
42
|
+
value: ''
|
|
43
43
|
}
|
|
44
44
|
},
|
|
45
45
|
motivation: 'commenting',
|
|
@@ -106,9 +106,10 @@ function MultipleBodyTemplate({
|
|
|
106
106
|
spacing: 2
|
|
107
107
|
}, /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
108
108
|
item: true
|
|
109
|
-
}, /*#__PURE__*/_react.default.createElement(
|
|
110
|
-
|
|
111
|
-
|
|
109
|
+
}, /*#__PURE__*/_react.default.createElement(_TextCommentInput.TextCommentInput, {
|
|
110
|
+
commentTemplates: commentTemplate,
|
|
111
|
+
comment: annotationState.maeData.textBody.value,
|
|
112
|
+
setComment: updateAnnotationTextualBodyValue,
|
|
112
113
|
t: t
|
|
113
114
|
})), /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
114
115
|
item: true
|
|
@@ -24,7 +24,7 @@ function TargetSpatialInput({
|
|
|
24
24
|
windowId
|
|
25
25
|
}) {
|
|
26
26
|
// TODO the targetSVGToolSTate is not used. Why the defaultToolState is used?
|
|
27
|
-
const [toolState, setToolState] = (0, _react.useState)(
|
|
27
|
+
const [toolState, setToolState] = (0, _react.useState)(_AnnotationFormUtils.TARGET_TOOL_STATE);
|
|
28
28
|
const [viewTool, setViewTool] = (0, _react.useState)(_AnnotationFormUtils.TARGET_VIEW);
|
|
29
29
|
const [scale, setScale] = (0, _react.useState)(playerReferences.getScale());
|
|
30
30
|
/** Change scale from container / canva */
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.TextCommentInput = TextCommentInput;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
|
+
var _material = require("@mui/material");
|
|
10
|
+
var _creatable = _interopRequireDefault(require("react-select/creatable"));
|
|
11
|
+
var _TextEditor = _interopRequireDefault(require("../TextEditor"));
|
|
12
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
+
/**
|
|
14
|
+
* TextCommentInput component
|
|
15
|
+
* @param commentTemplates - The list of comment templates
|
|
16
|
+
* @param comment - The current comment
|
|
17
|
+
* @param setComment - Function to set the comment
|
|
18
|
+
* @param t - Translation function
|
|
19
|
+
* @constructor
|
|
20
|
+
*/
|
|
21
|
+
function TextCommentInput({
|
|
22
|
+
commentTemplates,
|
|
23
|
+
comment,
|
|
24
|
+
setComment,
|
|
25
|
+
t
|
|
26
|
+
}) {
|
|
27
|
+
return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
28
|
+
container: true,
|
|
29
|
+
item: true
|
|
30
|
+
}, /*#__PURE__*/_react.default.createElement(_material.Typography, {
|
|
31
|
+
variant: "formSectionTitle"
|
|
32
|
+
}, t('note'))), commentTemplates.length > 0 && /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
33
|
+
item: true,
|
|
34
|
+
style: {
|
|
35
|
+
marginBottom: '10px'
|
|
36
|
+
}
|
|
37
|
+
}, /*#__PURE__*/_react.default.createElement(_creatable.default, {
|
|
38
|
+
options: commentTemplates.map(template => ({
|
|
39
|
+
label: template.title,
|
|
40
|
+
value: template.content,
|
|
41
|
+
title: template.content // Add title attribute for tooltip
|
|
42
|
+
})),
|
|
43
|
+
placeholder: t('useTemplate'),
|
|
44
|
+
onChange: selectedOption => {
|
|
45
|
+
if (selectedOption) {
|
|
46
|
+
setComment(selectedOption.value);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
isClearable: true,
|
|
50
|
+
isSearchable: true,
|
|
51
|
+
formatOptionLabel: option => /*#__PURE__*/_react.default.createElement("div", {
|
|
52
|
+
title: option.title
|
|
53
|
+
}, option.label),
|
|
54
|
+
styles: {
|
|
55
|
+
marginBottom: '20px'
|
|
56
|
+
}
|
|
57
|
+
})), /*#__PURE__*/_react.default.createElement(_material.Grid, {
|
|
58
|
+
container: true,
|
|
59
|
+
item: true
|
|
60
|
+
}, /*#__PURE__*/_react.default.createElement(_TextEditor.default, {
|
|
61
|
+
text: comment,
|
|
62
|
+
setText: setComment
|
|
63
|
+
})));
|
|
64
|
+
}
|
|
65
|
+
TextCommentInput.propTypes = {
|
|
66
|
+
comment: _propTypes.default.string.isRequired,
|
|
67
|
+
// eslint-disable-next-line react/forbid-prop-types
|
|
68
|
+
commentTemplates: _propTypes.default.arrayOf(_propTypes.default.object).isRequired,
|
|
69
|
+
setComment: _propTypes.default.func.isRequired,
|
|
70
|
+
t: _propTypes.default.func.isRequired
|
|
71
|
+
};
|
package/es/locales/locales_en.js
CHANGED
|
@@ -87,6 +87,7 @@ const en = exports.en = {
|
|
|
87
87
|
textual_note_with_target: 'Textual note with target',
|
|
88
88
|
tool_selection: 'Tool Selection',
|
|
89
89
|
unsupported_media_message: 'Your current canvas media type is not supported by the annotation editor.',
|
|
90
|
+
useTemplate: 'Use a template',
|
|
90
91
|
video_annotation_instruction: 'If you want to annotate video media, you must install MAEV to create and edit annotations on video:',
|
|
91
92
|
your_tag_here: 'Your tag here:',
|
|
92
93
|
zoom: 'Zoom'
|
package/es/locales/locales_fr.js
CHANGED
|
@@ -87,6 +87,7 @@ const fr = exports.fr = {
|
|
|
87
87
|
textual_note_with_target: 'Note textuelle avec cible',
|
|
88
88
|
tool_selection: 'Sélection d’outil',
|
|
89
89
|
unsupported_media_message: 'Le type de média de votre canvas actuel n\'est pas pris en charge par l\'éditeur d\'annotations.',
|
|
90
|
+
useTemplate: 'Utiliser un modèle',
|
|
90
91
|
video_annotation_instruction: 'Si vous souhaitez annoter des vidéos, vous devez installer le plugin Mirador Annotation Editor Video (MAEV) pour créer et modifier des annotations sur les vidéos :',
|
|
91
92
|
your_tag_here: 'Votre étiquette',
|
|
92
93
|
zoom: 'Zoom'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mirador-annotation-editor-video",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Mirador annotation editor video plugin in a React component. Mirador 4 (Alpha 2) compatible ",
|
|
5
5
|
"main": "es/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"prop-types": "^15.7.2",
|
|
64
64
|
"react": "^18.2.0",
|
|
65
65
|
"react-dom": "^18.0.0",
|
|
66
|
-
"uuid": "^
|
|
66
|
+
"uuid": "^11.0.0"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@babel/cli": "^7.25.9",
|
package/src/IIIFUtils.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
OVERLAY_TOOL,
|
|
6
6
|
SHAPES_TOOL,
|
|
7
7
|
} from './annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils';
|
|
8
|
-
import { TEMPLATE } from './annotationForm/AnnotationFormUtils';
|
|
8
|
+
import { TARGET_TOOL_STATE, TEMPLATE } from './annotationForm/AnnotationFormUtils';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Check if annotation is exportable to image in case of Konva annotation
|
|
@@ -136,8 +136,7 @@ export const getIIIFTargetFromMaeData = (
|
|
|
136
136
|
case TEMPLATE.MULTIPLE_BODY_TYPE:
|
|
137
137
|
case TEMPLATE.TEXT_TYPE:
|
|
138
138
|
// In some case the target can be simplified in a string
|
|
139
|
-
if (maeTarget.drawingState.shapes
|
|
140
|
-
&& maeTarget.drawingState.shapes[0].type === SHAPES_TOOL.RECTANGLE) {
|
|
139
|
+
if (isSimpleTarget(maeTarget.drawingState.shapes)) {
|
|
141
140
|
return getIIIFTargetFromRectangleShape(
|
|
142
141
|
maeTarget,
|
|
143
142
|
canvasId,
|
|
@@ -155,6 +154,11 @@ export const getIIIFTargetFromMaeData = (
|
|
|
155
154
|
return getIIIFTargetFullCanvas(maeData, canvasId);
|
|
156
155
|
};
|
|
157
156
|
|
|
157
|
+
const isSimpleTarget = (shapes) => shapes.length === 1
|
|
158
|
+
&& shapes[0].type === SHAPES_TOOL.RECTANGLE
|
|
159
|
+
&& shapes[0].strokeColor === TARGET_TOOL_STATE.strokeColor
|
|
160
|
+
&& shapes[0].fillColor === TARGET_TOOL_STATE.fillColor;
|
|
161
|
+
|
|
158
162
|
/**
|
|
159
163
|
* Get the IIIF target from a Konva annotation (Drawing template)
|
|
160
164
|
* @param maeData
|
package/src/TextEditor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import ReactQuill from 'react-quill';
|
|
4
4
|
import 'react-quill/dist/quill.snow.css';
|
|
@@ -12,20 +12,15 @@ const StyledReactQuill = styled(ReactQuill)(({ theme }) => ({
|
|
|
12
12
|
|
|
13
13
|
/** Rich text editor for annotation body */
|
|
14
14
|
function TextEditor({
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
text,
|
|
16
|
+
setText,
|
|
17
17
|
}) {
|
|
18
|
-
const [editorHtml, setEditorHtml] = useState(annoHtml);
|
|
19
|
-
|
|
20
18
|
/**
|
|
21
19
|
* Handle Change On ReactQuil Editor
|
|
22
20
|
* @param html
|
|
23
21
|
*/
|
|
24
22
|
const handleChange = (html) => {
|
|
25
|
-
|
|
26
|
-
if (updateAnnotationBody) {
|
|
27
|
-
updateAnnotationBody(html);
|
|
28
|
-
}
|
|
23
|
+
setText(html);
|
|
29
24
|
};
|
|
30
25
|
const modules = {
|
|
31
26
|
toolbar: [
|
|
@@ -63,7 +58,7 @@ function TextEditor({
|
|
|
63
58
|
return (
|
|
64
59
|
<div data-text-editor="name">
|
|
65
60
|
<StyledReactQuill
|
|
66
|
-
value={
|
|
61
|
+
value={text}
|
|
67
62
|
onChange={handleChange}
|
|
68
63
|
placeholder="Your text here"
|
|
69
64
|
bounds='[data-text-editor="name"]'
|
|
@@ -75,8 +70,8 @@ function TextEditor({
|
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
TextEditor.propTypes = {
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
setText: PropTypes.func.isRequired,
|
|
74
|
+
text: PropTypes.string.isRequired,
|
|
80
75
|
};
|
|
81
76
|
|
|
82
77
|
export default TextEditor;
|
|
@@ -112,7 +112,7 @@ export default function AnnotationFormBody(
|
|
|
112
112
|
saveAnnotation={saveAnnotation}
|
|
113
113
|
t={t}
|
|
114
114
|
windowId={windowId}
|
|
115
|
-
commentTemplate={config?.annotation?.
|
|
115
|
+
commentTemplate={config?.annotation?.commentTemplates ?? []}
|
|
116
116
|
tagsSuggestions={config?.annotation?.tagsSuggestions ?? []}
|
|
117
117
|
/>
|
|
118
118
|
)}
|
|
@@ -58,7 +58,8 @@ function AnnotationFormOverlayTool({
|
|
|
58
58
|
toolState.activeTool === OVERLAY_TOOL.EDIT && (
|
|
59
59
|
<>
|
|
60
60
|
{
|
|
61
|
-
currentShape && displayMode === KONVA_MODE.DRAW
|
|
61
|
+
((currentShape && displayMode === KONVA_MODE.DRAW)
|
|
62
|
+
|| (currentShape && displayMode === KONVA_MODE.TARGET)) && (
|
|
62
63
|
<div>
|
|
63
64
|
<Typography variant="subFormSectionTitle">
|
|
64
65
|
{t('selected_object')}
|
|
@@ -77,6 +78,7 @@ function AnnotationFormOverlayTool({
|
|
|
77
78
|
}}
|
|
78
79
|
setToolState={customUpdateToolState}
|
|
79
80
|
displayMode={displayMode}
|
|
81
|
+
currentShape={currentShape}
|
|
80
82
|
/>
|
|
81
83
|
</div>
|
|
82
84
|
)
|
|
@@ -139,7 +139,7 @@ function AnnotationFormOverlayToolOptions({
|
|
|
139
139
|
return (
|
|
140
140
|
<div>
|
|
141
141
|
{
|
|
142
|
-
(displayMode === KONVA_MODE.DRAW
|
|
142
|
+
((displayMode === KONVA_MODE.DRAW || displayMode === KONVA_MODE.TARGET)
|
|
143
143
|
&& isShapesTool(toolState.activeTool)) && (
|
|
144
144
|
<Grid container>
|
|
145
145
|
<ColorPicker
|
|
@@ -73,6 +73,7 @@ function Rectangle({
|
|
|
73
73
|
|
|
74
74
|
Rectangle.propTypes = {
|
|
75
75
|
activeTool: PropTypes.string.isRequired,
|
|
76
|
+
baseStrokeWidth: PropTypes.number.isRequired,
|
|
76
77
|
displayMode: PropTypes.string.isRequired,
|
|
77
78
|
handleDragEnd: PropTypes.func.isRequired,
|
|
78
79
|
handleDragStart: PropTypes.func.isRequired,
|
|
@@ -145,20 +145,16 @@ export const IMAGE_TOOL_STATE = {
|
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
147
|
* Specific Tool state for the target SVG
|
|
148
|
-
* @param imageZoom
|
|
149
|
-
* @returns {{activeTool: string, closedMode: string, image: {id: null}, imageEvent: null,
|
|
150
|
-
* strokeColor: string, strokeWidth: number}}
|
|
151
148
|
*/
|
|
152
|
-
export
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
149
|
+
export const TARGET_TOOL_STATE = {
|
|
150
|
+
activeTool: OVERLAY_TOOL.SHAPE,
|
|
151
|
+
closedMode: 'closed',
|
|
152
|
+
fillColor: 'rgba(100,100,100, 0)',
|
|
153
|
+
image: { id: null },
|
|
154
|
+
imageEvent: null,
|
|
155
|
+
strokeColor: 'rgba(255,0, 0, 0.5)',
|
|
156
|
+
strokeWidth: 5,
|
|
157
|
+
};
|
|
162
158
|
|
|
163
159
|
export const TARGET_VIEW = 'target';
|
|
164
160
|
export const OVERLAY_VIEW = 'layer';
|
|
@@ -28,9 +28,6 @@ export function MultiTagsInput({
|
|
|
28
28
|
<Typography variant="formSectionTitle">
|
|
29
29
|
{t('tags')}
|
|
30
30
|
</Typography>
|
|
31
|
-
{/* Show list of suggestions into a clickable tag */}
|
|
32
|
-
{/* add a toggle to show hide suggestions */}
|
|
33
|
-
|
|
34
31
|
<CreatableSelect
|
|
35
32
|
isMulti
|
|
36
33
|
options={mappedSuggestionsTags}
|
|
@@ -39,11 +36,9 @@ export function MultiTagsInput({
|
|
|
39
36
|
closeMenuOnSelect={false}
|
|
40
37
|
placeholder={t('tagsPlaceholder')}
|
|
41
38
|
/>
|
|
42
|
-
|
|
43
39
|
<Divider
|
|
44
40
|
spacing={2}
|
|
45
41
|
/>
|
|
46
|
-
|
|
47
42
|
</>
|
|
48
43
|
);
|
|
49
44
|
}
|
|
@@ -5,8 +5,8 @@ import AnnotationFormFooter from './AnnotationFormFooter';
|
|
|
5
5
|
import { TEMPLATE } from './AnnotationFormUtils';
|
|
6
6
|
import TargetFormSection from './TargetFormSection';
|
|
7
7
|
import { resizeKonvaStage } from './AnnotationFormOverlay/KonvaDrawing/KonvaUtils';
|
|
8
|
-
import TextFormSection from './TextFormSection';
|
|
9
8
|
import { MultiTagsInput } from './MultiTagsInput';
|
|
9
|
+
import { TextCommentInput } from './TextCommentInput';
|
|
10
10
|
|
|
11
11
|
/** Tagging Template* */
|
|
12
12
|
export default function MultipleBodyTemplate(
|
|
@@ -34,7 +34,7 @@ export default function MultipleBodyTemplate(
|
|
|
34
34
|
textBody: {
|
|
35
35
|
purpose: 'describing',
|
|
36
36
|
type: 'TextualBody',
|
|
37
|
-
value:
|
|
37
|
+
value: '',
|
|
38
38
|
},
|
|
39
39
|
},
|
|
40
40
|
motivation: 'commenting',
|
|
@@ -108,9 +108,10 @@ export default function MultipleBodyTemplate(
|
|
|
108
108
|
return (
|
|
109
109
|
<Grid container direction="column" spacing={2}>
|
|
110
110
|
<Grid item>
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
<TextCommentInput
|
|
112
|
+
commentTemplates={commentTemplate}
|
|
113
|
+
comment={annotationState.maeData.textBody.value}
|
|
114
|
+
setComment={updateAnnotationTextualBodyValue}
|
|
114
115
|
t={t}
|
|
115
116
|
/>
|
|
116
117
|
</Grid>
|
|
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import Typography from '@mui/material/Typography';
|
|
4
4
|
import { Grid } from '@mui/material';
|
|
5
5
|
import AnnotationDrawing from './AnnotationFormOverlay/AnnotationDrawing';
|
|
6
|
-
import {
|
|
6
|
+
import { TARGET_TOOL_STATE, TARGET_VIEW } from './AnnotationFormUtils';
|
|
7
7
|
import AnnotationFormOverlay from './AnnotationFormOverlay/AnnotationFormOverlay';
|
|
8
8
|
import { KONVA_MODE } from './AnnotationFormOverlay/KonvaDrawing/KonvaUtils';
|
|
9
9
|
|
|
@@ -16,7 +16,7 @@ export function TargetSpatialInput({
|
|
|
16
16
|
windowId,
|
|
17
17
|
}) {
|
|
18
18
|
// TODO the targetSVGToolSTate is not used. Why the defaultToolState is used?
|
|
19
|
-
const [toolState, setToolState] = useState(
|
|
19
|
+
const [toolState, setToolState] = useState(TARGET_TOOL_STATE);
|
|
20
20
|
const [viewTool, setViewTool] = useState(TARGET_VIEW);
|
|
21
21
|
const [scale, setScale] = useState(playerReferences.getScale());
|
|
22
22
|
/** Change scale from container / canva */
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Grid, Typography } from '@mui/material';
|
|
4
|
+
import CreatableSelect from 'react-select/creatable';
|
|
5
|
+
import TextEditor from '../TextEditor';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TextCommentInput component
|
|
9
|
+
* @param commentTemplates - The list of comment templates
|
|
10
|
+
* @param comment - The current comment
|
|
11
|
+
* @param setComment - Function to set the comment
|
|
12
|
+
* @param t - Translation function
|
|
13
|
+
* @constructor
|
|
14
|
+
*/
|
|
15
|
+
export function TextCommentInput({
|
|
16
|
+
commentTemplates,
|
|
17
|
+
comment,
|
|
18
|
+
setComment,
|
|
19
|
+
t,
|
|
20
|
+
}) {
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<Grid container item>
|
|
24
|
+
<Typography variant="formSectionTitle">
|
|
25
|
+
{t('note')}
|
|
26
|
+
</Typography>
|
|
27
|
+
</Grid>
|
|
28
|
+
{commentTemplates.length > 0 && (
|
|
29
|
+
<Grid item style={{ marginBottom: '10px' }}>
|
|
30
|
+
<CreatableSelect
|
|
31
|
+
options={commentTemplates.map((template) => ({
|
|
32
|
+
label: template.title,
|
|
33
|
+
value: template.content,
|
|
34
|
+
title: template.content, // Add title attribute for tooltip
|
|
35
|
+
}))}
|
|
36
|
+
placeholder={t('useTemplate')}
|
|
37
|
+
onChange={(selectedOption) => {
|
|
38
|
+
if (selectedOption) {
|
|
39
|
+
setComment(selectedOption.value);
|
|
40
|
+
}
|
|
41
|
+
}}
|
|
42
|
+
isClearable
|
|
43
|
+
isSearchable
|
|
44
|
+
formatOptionLabel={(option) => (
|
|
45
|
+
<div title={option.title}>
|
|
46
|
+
{option.label}
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
styles={{
|
|
50
|
+
marginBottom: '20px',
|
|
51
|
+
}}
|
|
52
|
+
/>
|
|
53
|
+
</Grid>
|
|
54
|
+
)}
|
|
55
|
+
|
|
56
|
+
<Grid container item>
|
|
57
|
+
<TextEditor
|
|
58
|
+
text={comment}
|
|
59
|
+
setText={setComment}
|
|
60
|
+
/>
|
|
61
|
+
</Grid>
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
TextCommentInput.propTypes = {
|
|
67
|
+
comment: PropTypes.string.isRequired,
|
|
68
|
+
// eslint-disable-next-line react/forbid-prop-types
|
|
69
|
+
commentTemplates: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
70
|
+
setComment: PropTypes.func.isRequired,
|
|
71
|
+
t: PropTypes.func.isRequired,
|
|
72
|
+
};
|
|
@@ -81,6 +81,7 @@ export const en = {
|
|
|
81
81
|
textual_note_with_target: 'Textual note with target',
|
|
82
82
|
tool_selection: 'Tool Selection',
|
|
83
83
|
unsupported_media_message: 'Your current canvas media type is not supported by the annotation editor.',
|
|
84
|
+
useTemplate: 'Use a template',
|
|
84
85
|
video_annotation_instruction: 'If you want to annotate video media, you must install MAEV to create and edit annotations on video:',
|
|
85
86
|
your_tag_here: 'Your tag here:',
|
|
86
87
|
zoom: 'Zoom',
|
|
@@ -81,6 +81,7 @@ export const fr = {
|
|
|
81
81
|
textual_note_with_target: 'Note textuelle avec cible',
|
|
82
82
|
tool_selection: 'Sélection d’outil',
|
|
83
83
|
unsupported_media_message: 'Le type de média de votre canvas actuel n\'est pas pris en charge par l\'éditeur d\'annotations.',
|
|
84
|
+
useTemplate: 'Utiliser un modèle',
|
|
84
85
|
video_annotation_instruction: 'Si vous souhaitez annoter des vidéos, vous devez installer le plugin Mirador Annotation Editor Video (MAEV) pour créer et modifier des annotations sur les vidéos :',
|
|
85
86
|
your_tag_here: 'Votre étiquette',
|
|
86
87
|
zoom: 'Zoom',
|