Skip to content

Commit 000abf8

Browse files
authored
persist doodles (#7)
* persist doodles * minor changes
1 parent d7718a4 commit 000abf8

File tree

11 files changed

+105
-5
lines changed

11 files changed

+105
-5
lines changed

.eslintcache

Whitespace-only changes.

src/annotator/components/toolbar.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ ToolbarButton.propTypes = {
7474
* Callback to toggle the visibility of the sidebar.
7575
* @prop {(object) => any} setDoodleOptions
7676
* Callback to set the options of the doodle canvas
77+
* @prop {() => any} saveDoodle
78+
* Callback to set the options of the doodle canvas
7779
* @prop {import("preact").Ref<HTMLButtonElement>} [toggleSidebarRef] -
7880
* Ref that gets set to the toolbar button for toggling the sidebar.
7981
* This is exposed to enable the drag-to-resize functionality of this
@@ -101,6 +103,7 @@ export default function Toolbar({
101103
toggleHighlights,
102104
toggleSidebar,
103105
setDoodleOptions,
106+
saveDoodle,
104107
toggleSidebarRef,
105108
useMinimalControls = false,
106109
drawingToolbarActivated,
@@ -191,6 +194,11 @@ export default function Toolbar({
191194
icon="erase"
192195
onClick={() => setDoodleOptions({ tool: 'eraser', size: 25 })}
193196
/>
197+
<ToolbarButton
198+
label="Save"
199+
icon="erase"
200+
onClick={() => saveDoodle()}
201+
/>
194202
</div>
195203
)}
196204
</div>
@@ -212,4 +220,5 @@ Toolbar.propTypes = {
212220
drawingToolbarActivated: propTypes.bool,
213221
drawingToolbarToggle: propTypes.func.isRequired,
214222
setDoodleOptions: propTypes.func.isRequired,
223+
saveDoodle: propTypes.func.isRequired,
215224
};

src/annotator/guest.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ export default class Guest extends Delegator {
360360
crossframe.on('setDoodleOptions', state => {
361361
this.setDoodleOptions(state);
362362
});
363+
364+
crossframe.on('saveCurrentDoodle', () => {
365+
this.saveCurrentDoodle();
366+
});
363367
}
364368

365369
destroy() {
@@ -585,6 +589,18 @@ export default class Guest extends Delegator {
585589
const setTargets = ([info, selectors]) => {
586590
// `selectors` is an array of arrays: each item is an array of selectors
587591
// identifying a distinct target.
592+
593+
// If the annotation is a doodle, add a target for the doodle lines
594+
if (annotation.$doodle && annotation.doodleLines) {
595+
selectors = [
596+
...selectors,
597+
annotation.doodleLines.map(curLine => ({
598+
type: 'DoodleSelector',
599+
line: curLine,
600+
})),
601+
];
602+
}
603+
588604
const source = info.uri;
589605
annotation.target = selectors.map(selector => ({
590606
source,
@@ -749,4 +765,16 @@ export default class Guest extends Delegator {
749765
}
750766
}
751767
}
768+
769+
/**
770+
* Save the doodle
771+
*/
772+
saveCurrentDoodle() {
773+
if (this.doodleCanvasController) {
774+
this.createAnnotation({
775+
$doodle: true,
776+
doodleLines: this.doodleCanvasController.lines,
777+
});
778+
}
779+
}
752780
}

src/annotator/sidebar.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ export default class Sidebar extends Guest {
137137
setHighlightsVisible: show => this.setAllVisibleHighlights(show),
138138
setUserCanDoodle: show => this.setAllDoodleability(show),
139139
setDoodleOptions: options => this.setAllDoodleOptions(options),
140+
saveDoodle: () => this.saveDoodle(),
140141
});
141142
this.toolbar.useMinimalControls = config.theme === 'clean';
142143

@@ -439,4 +440,11 @@ export default class Sidebar extends Guest {
439440
setAllDoodleOptions(options) {
440441
this.crossframe.call('setDoodleOptions', options);
441442
}
443+
444+
/**
445+
* (CreativeNTR) Save the doodle
446+
*/
447+
saveDoodle() {
448+
this.crossframe.call('saveCurrentDoodle');
449+
}
442450
}

src/annotator/toolbar.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Toolbar from './components/toolbar';
99
* @prop {(visible: boolean) => any} setHighlightsVisible
1010
* @prop {(doodleable: boolean) => any} setUserCanDoodle
1111
* @prop {(doodleable: boolean) => any} setDoodleOptions
12+
* @prop {() => any} saveDoodle
1213
*/
1314

1415
/**
@@ -29,6 +30,7 @@ export class ToolbarController {
2930
setHighlightsVisible,
3031
setUserCanDoodle,
3132
setDoodleOptions,
33+
saveDoodle,
3234
} = options;
3335

3436
this._container = container;
@@ -62,6 +64,9 @@ export class ToolbarController {
6264
createAnnotation();
6365
setSidebarOpen(true);
6466
};
67+
this._saveDoodle = () => {
68+
saveDoodle();
69+
};
6570

6671
/** Reference to the sidebar toggle button. */
6772
this._sidebarToggleButton = createRef();
@@ -148,6 +153,7 @@ export class ToolbarController {
148153
setDoodleOptions={this._setDoodleOptions}
149154
drawingToolbarActivated={this._drawingToolbar}
150155
drawingToolbarToggle={this._toggleDoodleToolbar}
156+
saveDoodle={this._saveDoodle}
151157
/>,
152158
this._container
153159
);

src/doodle/doodleCanvas.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import propTypes from 'prop-types';
99
* @prop {number} size - The size of the brush.
1010
* @prop {boolean} active - Whether the canvas can be doodled on at this time
1111
* @prop {HTMLElement} attachedElement - Which element the DoodleCanvas should cover.
12+
* @prop {Array<import('../types/api').DoodleLine>} lines - An array of lines that compose this doodle.
13+
* @prop {Function} setLines - A function to set the lines
1214
*/
1315

1416
/**
@@ -20,8 +22,14 @@ import propTypes from 'prop-types';
2022
*
2123
* @param {DoodleCanvasProps} props
2224
*/
23-
const DoodleCanvas = ({ tool, size, active, attachedElement }) => {
24-
const [lines, setLines] = useState(/** @type {array} */ ([]));
25+
const DoodleCanvas = ({
26+
tool,
27+
size,
28+
active,
29+
attachedElement,
30+
lines,
31+
setLines,
32+
}) => {
2533
const [isDrawing, setIsDrawing] = useState(false);
2634

2735
const handleMouseDown = e => {
@@ -103,6 +111,8 @@ DoodleCanvas.propTypes = {
103111
tool: propTypes.string.isRequired,
104112
size: propTypes.number.isRequired,
105113
active: propTypes.bool.isRequired,
114+
lines: propTypes.array.isRequired,
115+
setLines: propTypes.func.isRequired,
106116
attachedElement: propTypes.any.isRequired,
107117
};
108118

src/doodle/doodleController.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export class DoodleController {
88
*/
99
constructor(container, options) {
1010
const { tool, size } = options;
11+
this._lines = [];
1112

1213
this._container = container === null ? document.body : container;
1314
this._tool = tool;
@@ -30,6 +31,18 @@ export class DoodleController {
3031
return this._tool;
3132
}
3233

34+
/**
35+
* Update the lines and re-render on change
36+
*/
37+
set lines(newLines) {
38+
this._lines = newLines;
39+
this.render();
40+
}
41+
42+
get lines() {
43+
return this._lines;
44+
}
45+
3346
/**
3447
* Update the toolbar to reflect whether the "Create annotation" button will
3548
* create a page note (if there is no selection) or an annotation (if there is
@@ -58,12 +71,17 @@ export class DoodleController {
5871
}
5972

6073
render() {
74+
const setLines = newLines => {
75+
this.lines = newLines;
76+
};
6177
render(
6278
<DoodleCanvas
6379
attachedElement={this._container}
6480
size={this._size}
6581
tool={this._tool}
6682
active={this._doodleable}
83+
lines={this._lines}
84+
setLines={setLines}
6785
/>,
6886
document.body
6987
);

src/sidebar/services/annotations.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,6 @@ export default function annotationsService(api, store) {
170170
let saved;
171171

172172
const annotationWithChanges = applyDraftChanges(annotation);
173-
174173
if (metadata.isNew(annotation)) {
175174
saved = api.annotation.create({}, annotationWithChanges);
176175
} else {

src/sidebar/services/frame-sync.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ export default function FrameSync(annotationsService, bridge, store) {
182182
bridge.on('setDoodleOptions', function (state) {
183183
bridge.call('setDoodleOptions', state);
184184
});
185+
bridge.on('saveCurrentDoodle', function (state) {
186+
bridge.call('saveCurrentDoodle', state);
187+
});
185188
}
186189

187190
/**

src/types/annotator.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
/**
2222
* @typedef {import("./api").Selector} Selector
2323
* @typedef {import("./api").Target} Target
24+
* @typedef {import("./api").DoodleLine} DoodleLine
2425
*/
2526

2627
/**
@@ -30,6 +31,10 @@
3031
* @prop {string} uri
3132
* @prop {Target[]} target
3233
* @prop {string} $tag
34+
* @prop {boolean} [$doodle] -
35+
* Flag indicating that this annotation is a doodle
36+
* @prop {DoodleLine[]} [doodleLines] -
37+
* Array of lines that compose the doodle
3338
* @prop {boolean} [$highlight] -
3439
* Flag indicating that this annotation was created using the "Highlight" button,
3540
* as opposed to "Annotate".

0 commit comments

Comments
 (0)