return busy;
}
@VisibleForTesting // For testing with p/line container.
void extract(Element srcContainer, ContentRange previousSelection, BiasDirection cursorBias) {
final CMutableDocument destDoc = mutableDocument;
final OperationSequencer<Nindo> destOperationSequencer =
operationSequencer;
final LocationMapper<ContentNode> mapper = mutableDocument;
Point<ContentNode> start = normalize(previousSelection.getFirst());
Point<ContentNode> end = normalize(previousSelection.getSecond());
// Delete content if a range was selected
if (!previousSelection.isCollapsed()) {
PointRange<ContentNode> range = destDoc.deleteRange(start, end);
start = range.getFirst();
end = range.getSecond();
}
Point<ContentNode> insertAt = end;
int pos = mapper.getLocation(insertAt);
String waveXml = null;
String annotations = null;
if (useSemanticCopyPaste) {
waveXml = clipboard.maybeGetWaveXml(srcContainer);
annotations = clipboard.maybeGetAnnotations(srcContainer);
}
// TODO(user): Pass in whether the pasted content is rich or play
// TODO(patcoleman): once we have non rich-text paste, fix cursor bias correctly
cursorBias = BiasDirection.LEFT;
if (useSemanticCopyPaste && waveXml != null) {
if (!waveXml.isEmpty()) {
instrumentor.record(Action.CLIPBOARD_PASTE_FROM_WAVE);
// initialise the XML:
Builder builder = at(pos);
XmlStringBuilder createdFromXmlString =
XmlStringBuilder.createFromXmlStringWithContraints(waveXml,
PermittedCharacters.BLIP_TEXT);
// Strip annotations based on behaviour:
StringMap<String> modified = annotationLogic.stripKeys(
destDoc, pos, cursorBias, ContentType.RICH_TEXT, builder);
double startTime = Duration.currentTimeMillis();
// apply xml change
MutableDocumentImpl.appendXmlToBuilder(createdFromXmlString, builder);
double timeTaken = Duration.currentTimeMillis() - startTime;
LOG.trace().log("time taken: " + timeTaken);
// handle the end of annotations
annotationLogic.unstripKeys(builder, modified.keySet(), CollectionUtils.createStringSet());
builder.finish();
Nindo nindo = builder.build();
try {
validator.maybeThrowOperationExceptionFor(nindo);
int locationAfter = destDoc.getLocation(insertAt) + createdFromXmlString.getLength();
destOperationSequencer.begin();
destOperationSequencer.consume(nindo);
destOperationSequencer.end();
aggressiveSelectionHelper.setCaret(locationAfter);
LOG.trace().log("annotations: " + String.valueOf(annotations));
if (annotations != null && !annotations.isEmpty()) {
List<RangedAnnotation<String>> deserialize =
AnnotationSerializer.deserialize(annotations);
for (RangedAnnotation<String> ann : deserialize) {
destDoc.setAnnotation(pos + ann.start(), pos + ann.end(), ann.key(), ann.value());
LOG.trace().log(
"pos: " + pos + "start: " + (pos + ann.start()) + " end: " + (pos + ann.end())
+ " key: " + ann.key() + " value: " + ann.value());
}
}
} catch (OperationException e) {
LOG.error().log("Semantic paste failed");
// Restore caret
aggressiveSelectionHelper.setCaret(insertAt);
}
}
} else {
instrumentor.record(Action.CLIPBOARD_PASTE_FROM_OUTSIDE);
// initialize tokenizer and builder
RichTextTokenizer tokenizer = createTokenizer(srcContainer);
Builder builder = at(pos);
// handle annotation starts
StringMap<String> modified = annotationLogic.stripKeys(
destDoc, pos, cursorBias, ContentType.RICH_TEXT, builder);
// parse the tokens and apply ops
RichTextMutationBuilder mutationBuilder = new RichTextMutationBuilder(modified);
ReadableStringSet affectedKeys =
mutationBuilder.applyMutations(tokenizer, builder, destDoc, insertAt.getContainer());
// close annotations and finish
annotationLogic.unstripKeys(builder, modified.keySet(), affectedKeys);
builder.finish();
Nindo nindo = builder.build();
try {
validator.maybeThrowOperationExceptionFor(nindo);
destOperationSequencer.begin();
destOperationSequencer.consume(nindo);
destOperationSequencer.end();
int cursorLocation = pos + mutationBuilder.getLastGoodCursorOffset();
Point<ContentNode> caret = mapper.locate(cursorLocation);
aggressiveSelectionHelper.setCaret(caret);
} catch (OperationException e) {
LOG.error().log("Paste failed");
aggressiveSelectionHelper.setCaret(insertAt);
}
}
srcContainer.setInnerHTML("");
// Restore focus back to the editor
// TODO(user): Write a webdriver to test selection is correct after paste.
DomHelper.focus(destDoc.getDocumentElement().getContainerNodelet());
}