recogito / recogito-client-core

Core functions and components for RecogitoJS and Annotorious

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Adding multiple annotation bodies at the same time

Apeli opened this issue · comments

Hi, I'm trying to make a list of preselected values that would add a comment + colorcode to the annotation at the same time. I took the ColorSelectorWidget from https://recogito.github.io/guides/extending-the-editor/ as the base. I got to the point where I have the buttons, but when clicking on one, I can only set one body per click. So calling addTag the actual annotation only has 1 body, which ever is called last.

I tried like this:

var addTag = function(evt) {
args.onAppendBody({
                type: 'TextualBody',
                purpose: 'highlighting',
                value: evt.target.dataset.color,
            });

            args.onAppendBody({
                type: 'TextualBody',
                purpose: 'commenting',
                value: evt.target.dataset.tag,
            });
            ...

There the annotation only has the 'commenting' -body. Is there a way to set multiple bodies at the same time?

Good point - yes, interestingly no-one raised that as a requirement so far. It's not currently possible to add multiple bodies in one go. The onAppendBody method is async. Therefore, the second call essentially overwrites the first one.

If this is urgent: an ugly hack would be to delay the second call by a few milliseconds.

setTimeout(() => args.appendBody({...}), 1); // 1 might be sufficient to put it at the end of the queue

But for a clean solution, I'd need to extend the API with .onAppend/Update/UpsertBodies() methods. (Or simply make the current methods accept a single body or an array.)

Just moving this issue to the core module, which contains the code for the editor.

Thanks for a quick answer - but the setTimeout hack didn't work, 1/100/1000 ms delay made no difference. Any other hacks that come to mind :) ?

Yikes, of course... your widget is Vanilla Javascript, right? Not React... I totally forgot that in this case, the whole widget function will be destroyed an recreated. I.e. my suggested workaround isn't a workaround after all...

Hm, no I think there's no way to hack your way around this. At least not without touching the code of the Editor itself. Luckily, though, the code change required inside the editor si quite minimal. I'll see if I can get that done over the next day(s).

Yeah, I'm doing it in a vanilla js widget (which is used in a Vue component :))

The latest state on the main branch now has support for both this requirement (adding multiple bodies in one go), and saving immediately after an annotation update (#66). The key changes are:

  • .onAppendBody and .onRemoveBody now support a single body as well as an array of bodies as argument
  • Callback functions now have an extra saveImmediately argument (default false). Set it to true to save & close the editor immediately after performing the update.

For example, if you want to add two bodies and close immediately:

args.onAppendBody([ body1, body2 ], true);

P.S.: this still needs some testing, because it required a bit of a foundational change to the editor implementation. But otherwise it will go live with the next releases of Annotorious and RecogitoJS.

I changed the API to make this a bit cleaner + more flexible.

  • All the normal modification methods (onAppendBody, onRemoveBody, onUpdateBody, onUpsertBody) take only a single body as argument (and, optionally, a saveImmediately flag to close the editor)
  • There's a new method called onBatchModify(changes, saveImmedately) which takes a list of changes as argument.

Example:

const changes = [
  { action: 'append', body: bodyToAppend },
  { action: 'update', previous: prevBody, updated: updatedBody }
  { action: 'remove', body: bodyToRemove },

  // Normal upsert, previous is optional
  { action: 'upsert', previous: prevBody, updated: updatedBody }
   
  // Auto-upsert based on purpose    
  { action: 'upsert', body: bodyToUpser }
]

This keeps the original API as it was, plus provides a mechanism to apply any combination of modifications, with or without closing the editor immediately afterwards.