mirador-annotation-editor-video 1.0.0 → 1.0.93

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.
Files changed (67) hide show
  1. package/demo/src/index.js +5 -0
  2. package/demo/src/manifestsCatalog.js +2 -9
  3. package/es/CanvasListItem.js +4 -13
  4. package/es/IIIFUtils.js +142 -57
  5. package/es/TextEditor.js +27 -2
  6. package/es/annotationForm/AnnotationForm.js +16 -1
  7. package/es/annotationForm/AnnotationFormBody.js +13 -15
  8. package/es/annotationForm/AnnotationFormFooter.js +6 -0
  9. package/es/annotationForm/AnnotationFormOverlay/AnnotationDrawing.js +19 -8
  10. package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +4 -6
  11. package/es/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +5 -18
  12. package/es/annotationForm/AnnotationFormOverlay/ImageFormField.js +29 -5
  13. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils.js +46 -5
  14. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ArrowNode.js +0 -1
  15. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/CircleNode.js +6 -1
  16. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ColorPicker.js +1 -1
  17. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/EllipseNode.js +9 -4
  18. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/{Image.js → ImageShape.js} +22 -16
  19. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ParentComponent.js +15 -7
  20. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Polygon.js +6 -1
  21. package/es/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Rectangle.js +2 -1
  22. package/es/annotationForm/AnnotationFormUtils.js +17 -5
  23. package/es/annotationForm/DrawingTemplate.js +4 -2
  24. package/es/annotationForm/HMSInput.js +3 -3
  25. package/es/annotationForm/ImageCommentTemplate.js +3 -2
  26. package/es/annotationForm/MultiTagsInput.js +109 -0
  27. package/es/annotationForm/MultipleBodyTemplate.js +160 -0
  28. package/es/annotationForm/TargetSpatialInput.js +3 -2
  29. package/es/custom.css +135 -0
  30. package/es/locales/locales_en.js +5 -2
  31. package/es/locales/locales_fr.js +5 -2
  32. package/es/playerReferences.js +44 -9
  33. package/package.json +4 -3
  34. package/src/CanvasListItem.js +15 -20
  35. package/src/IIIFUtils.js +164 -60
  36. package/src/TextEditor.js +40 -2
  37. package/src/annotationForm/AnnotationForm.js +20 -2
  38. package/src/annotationForm/AnnotationFormBody.js +78 -83
  39. package/src/annotationForm/AnnotationFormFooter.js +5 -1
  40. package/src/annotationForm/AnnotationFormOverlay/AnnotationDrawing.js +20 -8
  41. package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayTool.js +37 -45
  42. package/src/annotationForm/AnnotationFormOverlay/AnnotationFormOverlayToolOptions.js +13 -28
  43. package/src/annotationForm/AnnotationFormOverlay/ImageFormField.js +56 -15
  44. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils.js +54 -4
  45. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ArrowNode.js +9 -4
  46. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/CircleNode.js +6 -1
  47. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ColorPicker.js +37 -31
  48. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/EllipseNode.js +17 -5
  49. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Freehand.js +10 -3
  50. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/{Image.js → ImageShape.js} +29 -19
  51. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/ParentComponent.js +10 -2
  52. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Polygon.js +9 -4
  53. package/src/annotationForm/AnnotationFormOverlay/KonvaDrawing/shapes/Rectangle.js +6 -3
  54. package/src/annotationForm/AnnotationFormUtils.js +16 -4
  55. package/src/annotationForm/DrawingTemplate.js +4 -0
  56. package/src/annotationForm/HMSInput.js +3 -3
  57. package/src/annotationForm/ImageCommentTemplate.js +2 -1
  58. package/src/annotationForm/MultiTagsInput.js +111 -0
  59. package/src/annotationForm/MultipleBodyTemplate.js +175 -0
  60. package/src/annotationForm/TargetSpatialInput.js +2 -1
  61. package/src/custom.css +135 -0
  62. package/src/locales/locales_en.js +5 -2
  63. package/src/locales/locales_fr.js +5 -2
  64. package/src/playerReferences.js +50 -8
  65. package/src/plugins/annotationCreationCompanionWindow.js +19 -7
  66. package/es/annotationForm/Debug.js +0 -143
  67. package/src/annotationForm/Debug.js +0 -202
package/demo/src/index.js CHANGED
@@ -6,7 +6,12 @@ import { manifestsCatalog } from './manifestsCatalog';
6
6
  const config = {
7
7
  annotation: {
8
8
  adapter: (canvasId) => new LocalStorageAdapter(`localStorage://?canvasId=${canvasId}`, 'Anonymous User'),
9
+ commentTemplate: '<h4>Comment</h4><p>comment content</p>',
9
10
  exportLocalStorageAnnotations: false, // display annotation JSON export button
11
+ tagsSuggestions: ['Mirador', 'Awesome', 'Viewer', 'IIIF'],
12
+ },
13
+ annotations: {
14
+ htmlSanitizationRuleSet: 'liberal',
10
15
  },
11
16
  catalog: manifestsCatalog,
12
17
  debug: true,
@@ -8,13 +8,6 @@ export const manifestsCatalog = [
8
8
  { manifestId: 'https://iiif.harvardartmuseums.org/manifests/object/299843' },
9
9
  { manifestId: 'https://iiif.io/api/cookbook/recipe/0002-mvm-audio/manifest.json' },
10
10
  { manifestId: 'https://files.tetras-libre.fr/dev/vertical_video_with_annot.json' },
11
- { manifestId: 'https://purl.stanford.edu/sn904cj3429/iiif/manifest' },
12
- { manifestId: 'https://coeso.tetras-libre.fr/data/coeso-deliverable/Manual_Network_Configuration.json' },
13
- { manifestId: 'https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json' },
14
- { manifestId: 'https://files.tetras-libre.fr/dev/multicanva-video.json' },
15
- { manifestId: 'https://dzkimgs.l.u-tokyo.ac.jp/videos/iiif_in_japan_2017/manifest.json' },
16
- { manifestId: 'https://iiif.io/api/cookbook/recipe/0219-using-caption-file/manifest.json' },
17
- { manifestId: 'https://preview.iiif.io/cookbook/master/recipe/0003-mvm-video/manifest.json' },
18
- { manifestId: 'https://iiif.io/api/cookbook/recipe/0065-opera-multiple-canvases/manifest.json' },
19
- { manifestId: 'https://iiif.io/api/cookbook/recipe/0064-opera-one-canvas/manifest.json' },
11
+ { manifestId: 'https://files.tetras-libre.fr/dev/youtube.json' },
12
+ { manifestId: 'https://files.tetras-libre.fr/dev/peertube.json' },
20
13
  ];
@@ -49,14 +49,6 @@ const CanvasListItem = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
49
49
  return annotation;
50
50
  }, [props.annotationid]);
51
51
 
52
- /**
53
- * Function to handle mouse hover event.
54
- * @function handleMouseHover
55
- * @returns {void}
56
- */
57
- const handleMouseHover = () => {
58
- setIsHovering(!isHovering);
59
- };
60
52
  /**
61
53
  * Handle deletion of annotation.
62
54
  * @function
@@ -125,8 +117,8 @@ const CanvasListItem = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
125
117
  t
126
118
  } = context;
127
119
  return /*#__PURE__*/_react.default.createElement("div", {
128
- onMouseEnter: handleMouseHover,
129
- onMouseLeave: handleMouseHover,
120
+ onMouseEnter: () => setIsHovering(true),
121
+ onMouseLeave: () => setIsHovering(false),
130
122
  className: "mirador-annotation-list-item",
131
123
  ref: ref
132
124
  }, isHovering && editable() && /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_ToggleButtonGroup.default, {
@@ -138,14 +130,13 @@ const CanvasListItem = /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
138
130
  right: 0,
139
131
  zIndex: 10000
140
132
  }
141
- }, /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
133
+ }, context?.config?.debug && /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
142
134
  title: t('debugAnnotation')
143
135
  }, /*#__PURE__*/_react.default.createElement(_ToggleButton.default, {
144
136
  "aria-label": "Debug",
145
137
  onClick: () => console.log(annotationData) // TODO Open IIIIF debug window
146
138
  ,
147
- value: "Debug in console",
148
- visible: context.config.debug
139
+ value: "Debug in console"
149
140
  }, /*#__PURE__*/_react.default.createElement(_Settings.default, null))), /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
150
141
  title: /*#__PURE__*/_react.default.createElement(_WhoAndWhenFormSection.default, {
151
142
  creator: annotationData.creator,
package/es/IIIFUtils.js CHANGED
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.maeTargetToIiifTarget = exports.convertAnnotationStateToBeSaved = void 0;
6
+ exports.getIIIFTargetFromMaeData = exports.convertAnnotationStateToBeSaved = void 0;
7
7
  var _KonvaUtils = require("./annotationForm/AnnotationFormOverlay/KonvaDrawing/KonvaUtils");
8
8
  var _AnnotationFormUtils = require("./annotationForm/AnnotationFormUtils");
9
9
  /**
@@ -31,13 +31,13 @@ function isAnnotationExportableToImage(maeData) {
31
31
  * @param playerReferences
32
32
  * @returns {Promise<void>}
33
33
  */
34
- const convertAnnotationStateToBeSaved = async (annotationState, canvas, windowId,
35
- // eslint-disable-next-line no-shadow
36
- playerReferences) => {
34
+ const convertAnnotationStateToBeSaved = async (annotationState, canvas, windowId, playerReferences) => {
37
35
  const annotationStateForSaving = annotationState;
38
36
  if (annotationState.maeData.templateType === _AnnotationFormUtils.TEMPLATE.IIIF_TYPE) {
39
37
  return annotationState;
40
38
  }
39
+ console.info('Annotation state to be saved', annotationState);
40
+ console.info('Annotation state target', annotationState.maeData.target);
41
41
 
42
42
  // TODO I dont know why this code is here? To clean the object ?
43
43
  annotationStateForSaving.maeData.target = {
@@ -47,86 +47,171 @@ playerReferences) => {
47
47
  tend: annotationStateForSaving.maeData.target.tend,
48
48
  tstart: annotationStateForSaving.maeData.target.tstart
49
49
  };
50
- if (annotationStateForSaving.maeData.templateType == _AnnotationFormUtils.TEMPLATE.TAGGING_TYPE || annotationStateForSaving.maeData.templateType == _AnnotationFormUtils.TEMPLATE.TEXT_TYPE) {
50
+ console.info('Annotation state target', annotationState.maeData.target);
51
+ if (annotationStateForSaving.maeData.templateType === _AnnotationFormUtils.TEMPLATE.TAGGING_TYPE || annotationStateForSaving.maeData.templateType === _AnnotationFormUtils.TEMPLATE.TEXT_TYPE || annotationStateForSaving.maeData.templateType === _AnnotationFormUtils.TEMPLATE.MANIFEST_TYPE || annotationStateForSaving.maeData.templateType === _AnnotationFormUtils.TEMPLATE.MULTIPLE_BODY_TYPE) {
51
52
  // Complex annotation
52
53
  if (annotationStateForSaving.maeData.target.drawingState.shapes.length > 0) {
53
- // eslint-disable-next-line no-param-reassign
54
54
  annotationStateForSaving.maeData.target.svg = await (0, _KonvaUtils.getSvg)(windowId);
55
55
  }
56
56
  }
57
+ if (annotationStateForSaving.maeData.templateType === _AnnotationFormUtils.TEMPLATE.MULTIPLE_BODY_TYPE) {
58
+ annotationStateForSaving.body = [annotationState.maeData.textBody];
59
+ annotationStateForSaving.body.push(...annotationState.maeData.tags.map(tag => ({
60
+ purpose: 'tagging',
61
+ type: 'TextualBody',
62
+ value: tag.text,
63
+ id: tag.id
64
+ })));
65
+ }
57
66
  if (isAnnotationExportableToImage(annotationStateForSaving.maeData)) {
58
67
  annotationStateForSaving.body.id = await (0, _KonvaUtils.getKonvaAsDataURL)(windowId);
59
68
  annotationStateForSaving.body.format = 'image/jpg';
60
69
  annotationStateForSaving.type = 'Annotation';
61
70
  }
62
- if (annotationStateForSaving.maeData.templateType == _AnnotationFormUtils.TEMPLATE.IMAGE_TYPE) {
63
- if (annotationStateForSaving.maeData.target.drawingState.shapes.length == 1) {
71
+ if (annotationStateForSaving.maeData.templateType === _AnnotationFormUtils.TEMPLATE.IMAGE_TYPE) {
72
+ if (annotationStateForSaving.maeData.target.drawingState.shapes.length === 1) {
64
73
  // eslint-disable-next-line max-len
65
74
  annotationStateForSaving.body.id = annotationStateForSaving.maeData.target.drawingState.shapes[0].url;
66
75
  annotationStateForSaving.type = 'Annotation';
67
76
  }
68
77
  }
69
-
70
- // eslint-disable-next-line no-param-reassign
71
78
  annotationStateForSaving.maeData.target.scale = playerReferences.getMediaTrueHeight() / playerReferences.getDisplayedMediaHeight() * playerReferences.getZoom();
72
-
73
- // eslint-disable-next-line no-param-reassign
74
- annotationStateForSaving.target = maeTargetToIiifTarget(annotationStateForSaving.maeData.target, canvas.id, playerReferences.getScale(), windowId);
75
- // eslint-disable-next-line no-param-reassign
79
+ annotationStateForSaving.target = getIIIFTargetFromMaeData(annotationStateForSaving.maeData, canvas.id, windowId, playerReferences.getScale());
76
80
  annotationStateForSaving.maeData.target.drawingState = JSON.stringify(annotationStateForSaving.maeData.target.drawingState);
77
81
  return annotationStateForSaving;
78
82
  };
79
83
 
80
- /** Transform maetarget to IIIF compatible data * */
84
+ /** Get the IIIF target from the annotation state
85
+ * @param maeData
86
+ * @param canvasId
87
+ * @param windowId NEEDED By MAEV
88
+ * @param playerScale NEEDED By MAEV
89
+ * @returns {{selector: [{type: string, value},{type: string, value: string}], source}|*|string}
90
+ */
81
91
  exports.convertAnnotationStateToBeSaved = convertAnnotationStateToBeSaved;
82
- const maeTargetToIiifTarget = (maeTarget, canvasId, playerScale, windowId = null) => {
83
- // In case of IIIF target, the user know what he is doing
84
- if (maeTarget.templateType === _AnnotationFormUtils.TEMPLATE.IIIF_TYPE) {
85
- return maeTarget;
92
+ const getIIIFTargetFromMaeData = (maeData, canvasId, windowId = null, playerScale = null) => {
93
+ const maeTarget = maeData.target;
94
+ const {
95
+ templateType
96
+ } = maeData;
97
+ switch (templateType) {
98
+ case _AnnotationFormUtils.TEMPLATE.IIIF_TYPE:
99
+ return maeTarget;
100
+ case _AnnotationFormUtils.TEMPLATE.KONVA_TYPE:
101
+ return getIIIFTargetFromKonvaType(maeData, canvasId);
102
+ case _AnnotationFormUtils.TEMPLATE.IMAGE_TYPE:
103
+ return getIIIFTargetFromImageType(maeData, canvasId, windowId, playerScale);
104
+ case _AnnotationFormUtils.TEMPLATE.TAGGING_TYPE:
105
+ case _AnnotationFormUtils.TEMPLATE.MANIFEST_TYPE:
106
+ case _AnnotationFormUtils.TEMPLATE.MULTIPLE_BODY_TYPE:
107
+ case _AnnotationFormUtils.TEMPLATE.TEXT_TYPE:
108
+ // In some case the target can be simplified in a string
109
+ if (maeTarget.drawingState.shapes.length === 1 && maeTarget.drawingState.shapes[0].type === _KonvaUtils.SHAPES_TOOL.RECTANGLE) {
110
+ return getIIIFTargetFromRectangleShape(maeTarget, canvasId, maeTarget.drawingState.shapes[0]);
111
+ }
112
+ // On the other case, the target is a SVG
113
+ console.info('Implement target as SVG/Fragment with shapes');
114
+ return getIIIFTargetAsFragmentSVGSelector(maeTarget, canvasId);
115
+ default:
116
+ return getIIIFTargetFullCanvas(maeData, canvasId);
86
117
  }
87
- if (maeTarget.templateType !== _AnnotationFormUtils.TEMPLATE.KONVA_TYPE) {
88
- // In some case the target can be simplify in a string
89
- if (maeTarget.drawingState.shapes.length === 1 && (maeTarget.drawingState.shapes[0].type === 'rectangle' || maeTarget.drawingState.shapes[0].type === 'image')) {
118
+
119
+ // Default return
120
+ return getIIIFTargetFullCanvas(maeData, canvasId);
121
+ };
122
+
123
+ /**
124
+ * Get the IIIF target from a Konva annotation (Drawing template)
125
+ * @param maeData
126
+ * @param canvasId
127
+ * @returns {`${string}#${string}`}
128
+ */
129
+ exports.getIIIFTargetFromMaeData = getIIIFTargetFromMaeData;
130
+ const getIIIFTargetFromKonvaType = (maeData, canvasId) => {
131
+ // Simplified target for Konva annotation
132
+ console.log('Implement target as string with Konva annotation');
133
+ return getIIIFTargetFullCanvas(maeData, canvasId);
134
+ };
135
+
136
+ /**
137
+ * Get the IIIF target from an annotation with image template
138
+ * @param maeData
139
+ * @param canvasId
140
+ * @param windowId
141
+ * @param playerScale
142
+ * @returns {string}
143
+ */
144
+ const getIIIFTargetFromImageType = (maeData, canvasId, windowId, playerScale) => {
145
+ const maeTarget = maeData.target;
146
+ if (maeTarget.drawingState.shapes.length === 1) {
147
+ if (maeTarget.drawingState.shapes[0].type === _KonvaUtils.OVERLAY_TOOL.IMAGE) {
90
148
  const {
91
- // eslint-disable-next-line prefer-const
92
149
  x,
93
- y,
94
- width,
95
- height,
96
- scaleX,
97
- scaleY
150
+ y
98
151
  } = maeTarget.drawingState.shapes[0];
99
- console.info('Implement target as string with one shape (reactangle or image)');
100
- // Image have not tstart and tend
101
- // We use scaleX and scaleY to have the real size of the shape, if it has been resized
102
- if (maeTarget.drawingState.shapes[0].type === 'image') {
103
- const imageShape = (0, _KonvaUtils.getKonvaShape)(windowId, maeTarget.drawingState.shapes[0].id);
104
- console.log('imageShape', imageShape);
105
- const widthImage = Math.round(imageShape.attrs.image.width * imageShape.attrs.scaleX / playerScale);
106
- const heightImage = Math.round(imageShape.attrs.image.height * imageShape.attrs.scaleY / playerScale);
107
- const xImage = Math.round(x / playerScale);
108
- const yImage = Math.round(y / playerScale);
109
- return `${canvasId}#${maeTarget.tend ? `xywh=${xImage},${yImage},${widthImage},${heightImage}&t=${maeTarget.tstart},${maeTarget.tend}` : `xywh=${xImage},${yImage},${widthImage},${heightImage}`}`;
110
- }
111
- return `${canvasId}#${maeTarget.tend ? `xywh=${x},${y},${width * scaleX},${height * scaleY}&t=${maeTarget.tstart},${maeTarget.tend}` : `xywh=${x},${y},${width * scaleX},${height * scaleY}`}`;
152
+ const imageShape = (0, _KonvaUtils.getKonvaShape)(windowId, maeTarget.drawingState.shapes[0].id);
153
+ const widthImage = Math.round(imageShape.attrs.image.width * imageShape.attrs.scaleX);
154
+ const heightImage = Math.round(imageShape.attrs.image.height * imageShape.attrs.scaleY);
155
+ const xImage = Math.round(x);
156
+ const yImage = Math.round(y);
157
+ return `${canvasId}#${maeTarget.tend ? `xywh=${xImage},${yImage},${widthImage},${heightImage}&t=${maeTarget.tstart},${maeTarget.tend}` : `xywh=${xImage},${yImage},${widthImage},${heightImage}`}`;
112
158
  }
113
- // On the other case, the target is a SVG
114
- console.info('Implement target as SVG/Fragment with shapes');
115
- const fragmentTarget = `${maeTarget.tend ? `xywh=${maeTarget.fullCanvaXYWH}&t=${maeTarget.tstart},${maeTarget.tend}` : `xywh=${maeTarget.fullCanvaXYWH}`}`;
116
- return {
117
- selector: [{
118
- type: 'SvgSelector',
119
- value: maeTarget.svg
120
- }, {
121
- type: 'FragmentSelector',
122
- value: `${canvasId}#${fragmentTarget}`
123
- }],
124
- source: canvasId
125
- };
126
159
  }
160
+ // Default return. For example if no image is upload in the annotation
161
+ return getIIIFTargetFullCanvas(maeData, canvasId);
162
+ };
127
163
 
128
- // In case of Konva target and for all the other case, target is a string and on full size canvas
129
- console.info('Implement target as string on fullSizeCanvas');
164
+ /**
165
+ * Get the IIIF target from the full canvas
166
+ * @param maeData
167
+ * @param canvasId
168
+ * @returns {`${string}#${string}`}
169
+ */
170
+ const getIIIFTargetFullCanvas = (maeData, canvasId) => {
171
+ console.info('Implement target as string on fullSizeCanvas.');
172
+ const maeTarget = maeData.target;
130
173
  return `${canvasId}#${maeTarget.tend ? `xywh=${maeTarget.fullCanvaXYWH}&t=${maeTarget.tstart},${maeTarget.tend}` : `xywh=${maeTarget.fullCanvaXYWH}`}`;
131
174
  };
132
- exports.maeTargetToIiifTarget = maeTargetToIiifTarget;
175
+
176
+ /**
177
+ * Get the IIIF target from a rectangle shape
178
+ * @param maeTarget
179
+ * @param canvasId
180
+ * @param shape
181
+ * @returns {`${string}#${string}`}
182
+ */
183
+ const getIIIFTargetFromRectangleShape = (maeTarget, canvasId, shape) => {
184
+ console.info('Implement target as string with one shape (rectangle)');
185
+ const {
186
+ x,
187
+ y,
188
+ width,
189
+ height,
190
+ scaleX,
191
+ scaleY
192
+ } = shape;
193
+
194
+ // Image have not tstart and tend
195
+ // We use scaleX and scaleY to have the real size of the shape, if it has been resized
196
+ return `${canvasId}#${maeTarget.tend ? `xywh=${x},${y},${width * scaleX},${height * scaleY}&t=${maeTarget.tstart},${maeTarget.tend}` : `xywh=${x},${y},${width * scaleX},${height * scaleY}`}`;
197
+ };
198
+
199
+ /**
200
+ * Get the IIIF target as a fragment selector with SVG
201
+ * @param maeTarget
202
+ * @param canvasId
203
+ * @returns {{selector: [{type: string, value},{type: string, value: string}], source}}
204
+ */
205
+ const getIIIFTargetAsFragmentSVGSelector = (maeTarget, canvasId) => {
206
+ const fragmentTarget = `${maeTarget.tend ? `t=${maeTarget.tstart},${maeTarget.tend}` : ''}`;
207
+ return {
208
+ selector: [{
209
+ type: 'SvgSelector',
210
+ value: maeTarget.svg
211
+ }, {
212
+ type: 'FragmentSelector',
213
+ value: `${canvasId}#${fragmentTarget}`
214
+ }],
215
+ source: canvasId
216
+ };
217
+ };
package/es/TextEditor.js CHANGED
@@ -37,10 +37,35 @@ function TextEditor({
37
37
  updateAnnotationBody(html);
38
38
  }
39
39
  };
40
- return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(StyledReactQuill, {
40
+ const modules = {
41
+ toolbar: [[{
42
+ header: [1, 2, false]
43
+ }], ['bold', 'italic', 'underline', 'strike', 'blockquote'], [{
44
+ list: 'ordered'
45
+ }, {
46
+ list: 'bullet'
47
+ }, {
48
+ indent: '-1'
49
+ }, {
50
+ indent: '+1'
51
+ }], [{
52
+ color: []
53
+ }, {
54
+ background: []
55
+ }], ['link', 'image'], ['clean']]
56
+ };
57
+ const formats = ['header', 'bold', 'italic', 'underline', 'strike', 'blockquote', 'list', 'bullet', 'indent', 'link', 'image', 'color', 'background'];
58
+
59
+ // Data field is needed to set bounds for the editor and avoir tooltip overflow
60
+ return /*#__PURE__*/_react.default.createElement("div", {
61
+ "data-text-editor": "name"
62
+ }, /*#__PURE__*/_react.default.createElement(StyledReactQuill, {
41
63
  value: editorHtml,
42
64
  onChange: handleChange,
43
- placeholder: "Your text here"
65
+ placeholder: "Your text here",
66
+ bounds: "[data-text-editor=\"name\"]",
67
+ modules: modules,
68
+ formats: formats
44
69
  }));
45
70
  }
46
71
  TextEditor.propTypes = {
@@ -17,6 +17,7 @@ var _AnnotationFormHeader = _interopRequireDefault(require("./AnnotationFormHead
17
17
  var _AnnotationFormBody = _interopRequireDefault(require("./AnnotationFormBody"));
18
18
  var _IIIFUtils = require("../IIIFUtils");
19
19
  require("../118n");
20
+ require("../custom.css");
20
21
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
21
22
  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); }
22
23
  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; }
@@ -37,6 +38,16 @@ function AnnotationForm({
37
38
  const [templateType, setTemplateType] = (0, _react.useState)(null);
38
39
  // eslint-disable-next-line no-underscore-dangle
39
40
  const [mediaType, setMediaType] = (0, _react.useState)(playerReferences.getMediaType());
41
+ const [containerWidth, setContainerWidth] = (0, _react.useState)(0);
42
+ const [retryCount, setRetryCount] = (0, _react.useState)(0);
43
+ const [, forceUpdate] = (0, _react.useReducer)(x => x + 1, 0);
44
+ if (!playerReferences.isInitializedCorrectly() && retryCount < 10) {
45
+ console.log('AnnotationForm.js: retryCount', retryCount);
46
+ setTimeout(() => {
47
+ setRetryCount(retryCount + 1);
48
+ forceUpdate();
49
+ }, 100);
50
+ }
40
51
 
41
52
  // Add a state to trigger redraw
42
53
  const [windowSize, setWindowSize] = (0, _react.useState)({
@@ -90,7 +101,10 @@ function AnnotationForm({
90
101
  window.removeEventListener('resize', handleResize);
91
102
  };
92
103
  }, []);
93
- if (!playerReferences?.isInitializedCorrectly()) {
104
+ if (!playerReferences.isInitCorrectly) {
105
+ playerReferences.isInitializedCorrectly();
106
+ }
107
+ if (!playerReferences.isInitCorrectly) {
94
108
  return /*#__PURE__*/_react.default.createElement(_CompanionWindow.default, {
95
109
  title: t('media_not_supported'),
96
110
  windowId: windowId,
@@ -164,6 +178,7 @@ function AnnotationForm({
164
178
  annotation: annotation,
165
179
  canvases: canvases,
166
180
  closeFormCompanionWindow: closeFormCompanionWindow,
181
+ config: config,
167
182
  debugMode: debugMode,
168
183
  playerReferences: playerReferences,
169
184
  saveAnnotation: saveAnnotation,
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = AnnotationFormBody;
7
- var _react = _interopRequireWildcard(require("react"));
7
+ var _react = _interopRequireDefault(require("react"));
8
8
  var _propTypes = _interopRequireDefault(require("prop-types"));
9
9
  var _styles = require("@mui/material/styles");
10
10
  var _material = require("@mui/material");
@@ -17,10 +17,8 @@ var _DrawingTemplate = _interopRequireDefault(require("./DrawingTemplate"));
17
17
  var _IIIFTemplate = _interopRequireDefault(require("./IIIFTemplate"));
18
18
  var _TaggingTemplate = _interopRequireDefault(require("./TaggingTemplate"));
19
19
  require("./debug.css");
20
- var _AdvancedAnnotationEditor = require("./AdvancedAnnotationEditor");
20
+ var _MultipleBodyTemplate = _interopRequireDefault(require("./MultipleBodyTemplate"));
21
21
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
22
- 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); }
23
- 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; }
24
22
  /**
25
23
  * This function contain the logic for loading annotation and render proper template type
26
24
  * * */
@@ -28,6 +26,7 @@ function AnnotationFormBody({
28
26
  annotation,
29
27
  canvases,
30
28
  closeFormCompanionWindow,
29
+ config,
31
30
  debugMode,
32
31
  playerReferences,
33
32
  saveAnnotation,
@@ -35,11 +34,10 @@ function AnnotationFormBody({
35
34
  templateType,
36
35
  windowId
37
36
  }) {
38
- const [showAdvanced, setShowAdvanced] = (0, _react.useState)(false);
39
37
  return /*#__PURE__*/_react.default.createElement(_material.Grid, {
40
38
  container: true,
41
39
  direction: "column"
42
- }, !showAdvanced && /*#__PURE__*/_react.default.createElement(TemplateContainer, {
40
+ }, /*#__PURE__*/_react.default.createElement(TemplateContainer, {
43
41
  item: true
44
42
  }, templateType.id === _AnnotationFormUtils.TEMPLATE.TEXT_TYPE && /*#__PURE__*/_react.default.createElement(_TextCommentTemplate.default, {
45
43
  annotation: annotation,
@@ -83,17 +81,15 @@ function AnnotationFormBody({
83
81
  saveAnnotation: saveAnnotation,
84
82
  t: t,
85
83
  windowId: windowId
86
- })), /*#__PURE__*/_react.default.createElement(_material.Grid, {
87
- item: true
88
- }, showAdvanced && /*#__PURE__*/_react.default.createElement(_AdvancedAnnotationEditor.AdvancedAnnotationEditor, {
89
- value: annotation,
90
- onChange: updatedAnnotation => {
91
- // eslint-disable-next-line no-param-reassign
92
- annotation = updatedAnnotation;
93
- },
84
+ }), templateType.id === _AnnotationFormUtils.TEMPLATE.MULTIPLE_BODY_TYPE && /*#__PURE__*/_react.default.createElement(_MultipleBodyTemplate.default, {
85
+ annotation: annotation,
94
86
  closeFormCompanionWindow: closeFormCompanionWindow,
87
+ playerReferences: playerReferences,
95
88
  saveAnnotation: saveAnnotation,
96
- t: t
89
+ t: t,
90
+ windowId: windowId,
91
+ commentTemplate: config?.annotation?.commentTemplate ?? '',
92
+ tagsSuggestions: config?.annotation?.tagsSuggestions ?? []
97
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())));
98
94
  }
99
95
  const TemplateContainer = (0, _styles.styled)(_material.Grid)({
@@ -113,6 +109,8 @@ AnnotationFormBody.propTypes = {
113
109
  // eslint-disable-next-line react/forbid-prop-types
114
110
  canvases: _propTypes.default.object.isRequired,
115
111
  closeFormCompanionWindow: _propTypes.default.func.isRequired,
112
+ // eslint-disable-next-line react/forbid-prop-types
113
+ config: _propTypes.default.object.isRequired,
116
114
  debugMode: _propTypes.default.bool.isRequired,
117
115
  // eslint-disable-next-line react/forbid-prop-types
118
116
  playerReferences: _propTypes.default.object.isRequired,
@@ -46,10 +46,16 @@ function AnnotationFormFooter({
46
46
  }, /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
47
47
  title: t('cancel')
48
48
  }, /*#__PURE__*/_react.default.createElement(_material.Button, {
49
+ sx: {
50
+ m: 1
51
+ },
49
52
  onClick: closeFormCompanionWindow
50
53
  }, t('cancel'))), /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
51
54
  title: t('save')
52
55
  }, /*#__PURE__*/_react.default.createElement(_material.Button, {
56
+ sx: {
57
+ m: 1
58
+ },
53
59
  variant: "contained",
54
60
  color: "primary",
55
61
  type: "submit",
@@ -22,6 +22,7 @@ function AnnotationDrawing({
22
22
  scale,
23
23
  setColorToolFromCurrentShape,
24
24
  setDrawingState,
25
+ setToolState,
25
26
  tabView,
26
27
  toolState,
27
28
  updateCurrentShapeInShapes,
@@ -39,16 +40,16 @@ function AnnotationDrawing({
39
40
  width
40
41
  }]);
41
42
  (0, _react.useEffect)(() => {
42
- if (toolState.imageEvent?.id) {
43
+ if (toolState.imageEvent?.id && !drawingState.currentShape) {
43
44
  const imageShape = {
44
45
  id: (0, _uuid.v4)(),
45
46
  rotation: 0,
46
- scaleX: 1,
47
- scaleY: 1,
47
+ scaleX: 0.2,
48
+ scaleY: 0.2,
48
49
  type: _KonvaUtils.OVERLAY_TOOL.IMAGE,
49
50
  url: toolState.imageEvent.id,
50
- x: 30,
51
- y: 30
51
+ x: 60,
52
+ y: 60
52
53
  };
53
54
  setDrawingState({
54
55
  ...drawingState,
@@ -112,13 +113,21 @@ function AnnotationDrawing({
112
113
  const shapesWithoutTheDeleted = drawingState.shapes.filter(shape => shape.id !== drawingState.currentShape.id);
113
114
  setDrawingState({
114
115
  ...drawingState,
116
+ currentShape: null,
115
117
  shapes: shapesWithoutTheDeleted
116
118
  });
119
+ setToolState({
120
+ ...toolState,
121
+ imageEvent: null
122
+ });
117
123
  return;
118
124
  }
119
125
 
120
126
  // release the drawing
121
127
  if (e.key === 'Escape') {
128
+ if (toolState.activeTool === _KonvaUtils.OVERLAY_TOOL.IMAGE) {
129
+ return;
130
+ }
122
131
  if (toolState.activeTool === _KonvaUtils.SHAPES_TOOL.POLYGON) {
123
132
  drawingState.currentShape.points.splice(-2, 2);
124
133
  updateCurrentShapeInShapes({
@@ -187,7 +196,7 @@ function AnnotationDrawing({
187
196
  const modifiedShape = evt.target.attrs;
188
197
  const shape = drawingState.shapes.find(s => s.id === modifiedShape.id);
189
198
  Object.assign(shape, modifiedShape);
190
- if (shape.type === 'image') {
199
+ if (shape.type === _KonvaUtils.OVERLAY_TOOL.IMAGE) {
191
200
  shape.width = modifiedShape.image.width * modifiedShape.scaleX;
192
201
  shape.height = modifiedShape.image.height * modifiedShape.scaleY;
193
202
  }
@@ -204,7 +213,7 @@ function AnnotationDrawing({
204
213
  Object.assign(shape, editedShape);
205
214
  shape.x = editedShape.x;
206
215
  shape.y = editedShape.y;
207
- if (shape.type === 'image') {
216
+ if (shape.type === _KonvaUtils.SHAPES_TOOL.IMAGE) {
208
217
  shape.width = editedShape.image.width * editedShape.scaleX;
209
218
  shape.height = editedShape.image.height * editedShape.scaleY;
210
219
  }
@@ -296,7 +305,7 @@ function AnnotationDrawing({
296
305
  shapes: [...drawingState.shapes, shape]
297
306
  });
298
307
  break;
299
- case 'text':
308
+ case _KonvaUtils.OVERLAY_TOOL.TEXT:
300
309
  shape = {
301
310
  fill: toolState.fillColor,
302
311
  fontSize: 20,
@@ -513,6 +522,7 @@ function AnnotationDrawing({
513
522
  id: windowId
514
523
  }, /*#__PURE__*/_react.default.createElement(_ParentComponent.default, {
515
524
  activeTool: toolState.activeTool,
525
+ baseStrokeWidth: playerReferences.getTargetStrokeWidth(),
516
526
  displayMode: displayMode,
517
527
  handleDragEnd: handleDragEnd,
518
528
  handleDragStart: handleDragStart,
@@ -591,6 +601,7 @@ AnnotationDrawing.propTypes = {
591
601
  scale: _propTypes.default.number.isRequired,
592
602
  setColorToolFromCurrentShape: _propTypes.default.func.isRequired,
593
603
  setDrawingState: _propTypes.default.func.isRequired,
604
+ setToolState: _propTypes.default.func.isRequired,
594
605
  tabView: _propTypes.default.string.isRequired,
595
606
  toolState: _propTypes.default.oneOfType(_propTypes.default.string, _propTypes.default.string, _propTypes.default.string, _propTypes.default.oneOfType(_propTypes.default.string), _propTypes.default.string, _propTypes.default.string, _propTypes.default.number).isRequired,
596
607
  updateCurrentShapeInShapes: _propTypes.default.func.isRequired,
@@ -81,16 +81,14 @@ function AnnotationFormOverlayTool({
81
81
  deleteShape: deleteShape,
82
82
  updateCurrentShapeInShapes: updateCurrentShapeInShapes,
83
83
  t: t
84
- }))), (0, _KonvaUtils.isShapesTool)(toolState.activeTool) && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.default, {
85
- variant: "subFormSectionTitle"
86
- }, t('shape')), /*#__PURE__*/_react.default.createElement(_AnnotationFormUtils.StyledToggleButtonGroup, {
84
+ }))), (0, _KonvaUtils.isShapesTool)(toolState.activeTool) && /*#__PURE__*/_react.default.createElement(_AnnotationFormUtils.StyledToggleButtonGroup, {
87
85
  value: toolState.activeTool // State or props ?
88
86
  ,
89
87
  exclusive: true,
90
88
  onChange: changeTool,
91
89
  "aria-label": t('tool_selection'),
92
90
  size: "small"
93
- }, /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
91
+ }, displayMode !== _KonvaUtils.KONVA_MODE.IMAGE && /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
94
92
  title: t('rectangle')
95
93
  }, /*#__PURE__*/_react.default.createElement(_ToggleButton.default, {
96
94
  value: _KonvaUtils.SHAPES_TOOL.RECTANGLE,
@@ -100,7 +98,7 @@ function AnnotationFormOverlayTool({
100
98
  }, /*#__PURE__*/_react.default.createElement(_ToggleButton.default, {
101
99
  value: _KonvaUtils.SHAPES_TOOL.CIRCLE,
102
100
  "aria-label": t('add_a_circle')
103
- }, /*#__PURE__*/_react.default.createElement(_RadioButtonUnchecked.default, null))), /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
101
+ }, /*#__PURE__*/_react.default.createElement(_RadioButtonUnchecked.default, null))), displayMode !== _KonvaUtils.KONVA_MODE.IMAGE && /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_material.Tooltip, {
104
102
  title: t('line')
105
103
  }, /*#__PURE__*/_react.default.createElement(_ToggleButton.default, {
106
104
  value: _KonvaUtils.SHAPES_TOOL.POLYGON,
@@ -115,7 +113,7 @@ function AnnotationFormOverlayTool({
115
113
  }, /*#__PURE__*/_react.default.createElement(_ToggleButton.default, {
116
114
  value: _KonvaUtils.SHAPES_TOOL.ARROW,
117
115
  "aria-label": t('add_an_arrow_shape')
118
- }, /*#__PURE__*/_react.default.createElement(_ArrowOutward.default, null)))))), toolState.activeTool === _KonvaUtils.OVERLAY_TOOL.DELETE && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.default, {
116
+ }, /*#__PURE__*/_react.default.createElement(_ArrowOutward.default, null))))), toolState.activeTool === _KonvaUtils.OVERLAY_TOOL.DELETE && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_Typography.default, {
119
117
  variant: "overline"
120
118
  }, t('delete')), /*#__PURE__*/_react.default.createElement("p", null, t('click_to_delete_shape')), /*#__PURE__*/_react.default.createElement(_material.Button, {
121
119
  onClick: () => deleteShape()