package org.swellrt.beta.client.js.editor.annotation; import java.util.Map; import org.waveprotocol.wave.client.editor.EditorContext; import org.waveprotocol.wave.client.editor.content.CMutableDocument; import org.waveprotocol.wave.client.editor.content.ContentElement; import org.waveprotocol.wave.client.editor.content.ContentNode; import org.waveprotocol.wave.client.editor.content.misc.CaretAnnotations; import org.waveprotocol.wave.client.editor.content.paragraph.Paragraph; import org.waveprotocol.wave.client.editor.content.paragraph.Paragraph.Alignment; import org.waveprotocol.wave.client.editor.content.paragraph.Paragraph.EventHandler; import org.waveprotocol.wave.client.editor.content.paragraph.Paragraph.MutationHandler; import org.waveprotocol.wave.client.editor.content.paragraph.ParagraphBehaviour; import org.waveprotocol.wave.model.document.MutableAnnotationSet; import org.waveprotocol.wave.model.document.indexed.LocationMapper; import org.waveprotocol.wave.model.document.util.Range; import com.google.gwt.user.client.Event; /** * Paragraph annotation type. See internals in {@See Paragraph}. * * @author pablojan@gmail.com (Pablo Ojanguren) * */ public class ParagraphValueAnnotation implements ParagraphAnnotation, Annotation.Listenable, EventHandler, MutationHandler { private final String name; private final Map<String, Paragraph.LineStyle> styles; private final AttributeGenerator attributeGen; private final ParagraphBehaviour behaviour; private AnnotationInstance.Handler handler; public ParagraphValueAnnotation(ParagraphBehaviour behaviour, String name, Map<String, Paragraph.LineStyle> styles, AttributeGenerator attributeGen) { this.name = name; this.styles = styles; this.attributeGen = attributeGen; this.behaviour = behaviour; } public String getName() { return name; } @Override public void set(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String value) { if (range != null && doc != null) { if (value != null && !value.isEmpty() && !styles.containsKey(value)) return; final boolean isOn = (value != null && !value.isEmpty() && !value.equals("default")); if (!isOn) value = "default"; Paragraph.LineStyle style = styles.get(value); if (attributeGen != null) style.setAttributes(attributeGen.generate(range, value)); Paragraph.apply(mapper, range.getStart(), range.getEnd(), style, isOn); style.setAttributes(null); } } @Override public void reset(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range) { set(doc, mapper, localAnnotations, caret, range, null); } public String apply(EditorContext editor, Range range) { for (String styleValue: styles.keySet()) { if (Paragraph.appliesEntirely(editor.getDocument(), range.getStart(), range.getEnd(), styles.get(styleValue))) { return styleValue.equals("default") ? null : styleValue; } } return null; } public String apply(ContentElement e) { final String[] result = new String[1]; this.styles.forEach( (value , style) -> { if (!value.equals("default") && style.isApplied(e)) result[0] = value; }); return result[0]; } @Override public void update(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String value) { // do not implement } @Override public Range mutate(CMutableDocument doc, LocationMapper<ContentNode> mapper, MutableAnnotationSet<Object> localAnnotations, CaretAnnotations caret, Range range, String text, String value) { return null; } @Override public void setHandler(AnnotationInstance.Handler h) { this.handler = h; Paragraph.registerEventHandler(behaviour, this); Paragraph.registerMutationHandler(behaviour, this); } private static String getParagraphAnnotationValue(ContentElement node, ParagraphBehaviour behaviour) { if (ParagraphBehaviour.DEFAULT.equals(behaviour)) { return Alignment.fromValue(node.asElement().getAttribute(Paragraph.ALIGNMENT_ATTR)).cssValue(); } else if (ParagraphBehaviour.HEADING.equals(behaviour)) { return node.asElement().getAttribute(Paragraph.SUBTYPE_ATTR); } else if (ParagraphBehaviour.LIST.equals(behaviour)) { return node.asElement().getAttribute(Paragraph.LIST_STYLE_ATTR); } return null; } @Override public void onAdded(ContentElement node) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = getParagraphAnnotationValue(node, behaviour); handler.exec(AnnotationInstance.EVENT_ADDED, AnnotationInstance.create(name, value, node), null); } } @Override public void onMutation(ContentElement node) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = getParagraphAnnotationValue(node, behaviour); handler.exec(AnnotationInstance.EVENT_MUTATED, AnnotationInstance.create(name, value, node), null); } } @Override public void onRemoved(ContentElement node) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = getParagraphAnnotationValue(node, behaviour); handler.exec(AnnotationInstance.EVENT_REMOVED, AnnotationInstance.create(name, value, node), null); } } @Override public void onEvent(ContentElement node, Event event) { if (handler != null && !AnnotationRegistry.muteHandlers) { String value = getParagraphAnnotationValue(node, behaviour); handler.exec(AnnotationInstance.EVENT_MOUSE, AnnotationInstance.create(name, value, node), event); } } }