mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-26 00:02:06 +01:00
Add support for XEP-0394: Message Markup
Fixes SMACK-794.
This commit is contained in:
parent
b3b76b9ff4
commit
a729a7c43b
13 changed files with 1167 additions and 0 deletions
|
@ -98,6 +98,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental
|
||||||
| [OMEMO Multi End Message and Object Encryption](omemo.md) | [XEP-XXXX](https://conversations.im/omemo/xep-omemo.html) | Encrypt messages using OMEMO encryption (currently only with smack-omemo-signal -> GPLv3). |
|
| [OMEMO Multi End Message and Object Encryption](omemo.md) | [XEP-XXXX](https://conversations.im/omemo/xep-omemo.html) | Encrypt messages using OMEMO encryption (currently only with smack-omemo-signal -> GPLv3). |
|
||||||
| [Consistent Color Generation](consistent_colors.md) | [XEP-0392](http://xmpp.org/extensions/xep-0392.html) | Generate consistent colors for identifiers like usernames to provide a consistent user experience. |
|
| [Consistent Color Generation](consistent_colors.md) | [XEP-0392](http://xmpp.org/extensions/xep-0392.html) | Generate consistent colors for identifiers like usernames to provide a consistent user experience. |
|
||||||
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
| Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers |
|
||||||
|
| [Message Markup](messagemarkup.md) | [XEP-0394](http://xmpp.org/extensions/xep-0394.html)| Style message bodies while keeping body and markup information separated. |
|
||||||
|
|
||||||
|
|
||||||
Legacy Smack Extensions and currently supported XEPs of smack-legacy
|
Legacy Smack Extensions and currently supported XEPs of smack-legacy
|
||||||
|
|
68
documentation/extensions/messagemarkup.md
Normal file
68
documentation/extensions/messagemarkup.md
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
Message Markup
|
||||||
|
==============
|
||||||
|
|
||||||
|
[Back](index.md)
|
||||||
|
|
||||||
|
[Message Markup (XEP-0394)](https://xmpp.org/extensions/xep-0394.html) can be used as a an alternative to XHTML-IM to style messages, while keeping the body and markup information strictly separated.
|
||||||
|
This implementation can *not* be used to render message bodies, but will offer a simple to use interface for creating ExtensionElements which encode the markup information.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
The most important class is the `MarkupElement` class, which contains a Builder.
|
||||||
|
|
||||||
|
To start creating a Message Markup Extension, call `MarkupElement.getBuilder()`.
|
||||||
|
(Almost) all method calls documented below will be made on the builder.
|
||||||
|
|
||||||
|
Whenever a method call receives a `start` and `end` index, `start` represents the first character, which is affected by the styling, while `end` is the character *after* the last affected character.
|
||||||
|
|
||||||
|
### Inline styling
|
||||||
|
|
||||||
|
Currently there are 3 styles available:
|
||||||
|
* *emphasis*, which should be rendered by a client as *italic*, or **bold**
|
||||||
|
* *code*, which should be rendered in `monospace`
|
||||||
|
* *deleted*, which should be rendered as ~~strikethrough~~.
|
||||||
|
|
||||||
|
Those styles are available by calling `builder.setEmphasis(int start, int end)`,
|
||||||
|
`builder.setDeleted(int start, int end)` and `builder.setCode(int start, int end)`.
|
||||||
|
|
||||||
|
If you want to apply multiple inline styles to a section, you can do the following:
|
||||||
|
```
|
||||||
|
Set<SpanElement.SpanStyle> spanStyles = new HashSet<>();
|
||||||
|
styles.add(SpanElement.SpanStyle.emphasis);
|
||||||
|
styles.add(SpanElement.SpanStyle.deleted);
|
||||||
|
builder.addSpan(start, end, spanStyles);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, that spans cannot overlap one another.
|
||||||
|
|
||||||
|
### Block Level Styling
|
||||||
|
|
||||||
|
Available block level styles are:
|
||||||
|
* Code blocks, which should be rendered as
|
||||||
|
```
|
||||||
|
blocks
|
||||||
|
of
|
||||||
|
code
|
||||||
|
```
|
||||||
|
|
||||||
|
* Itemized lists, which should render as
|
||||||
|
* Lists
|
||||||
|
* with possibly multiple
|
||||||
|
* entries
|
||||||
|
|
||||||
|
* Block Quotes, which should be rendered by the client
|
||||||
|
> as quotes, which
|
||||||
|
>> also can be nested
|
||||||
|
|
||||||
|
To mark a section as code block, call `builder.setCodeBlock(start, end)`.
|
||||||
|
|
||||||
|
To create a list, call `MarkupElement.Builder.ListBuilder lbuilder = builder.beginList()`, which will return a list builder.
|
||||||
|
On this you can call `lbuilder.addEntry(start, end)` to add an entry.
|
||||||
|
|
||||||
|
Note: If you add an entry, the start value MUST be equal to the end value of the previous added entry!
|
||||||
|
|
||||||
|
To end the list, call `lbuilder.endList()`, which will return the MessageMarkup builder.
|
||||||
|
|
||||||
|
To create a block quote, call `builder.setBlockQuote(start, end)`.
|
||||||
|
|
||||||
|
Note that block level elements MUST NOT overlap each other boundaries, but may be fully contained (nested) within each other.
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class BlockQuoteElement implements MarkupElement.BlockLevelMarkupElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "bquote";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Block Quote element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
*/
|
||||||
|
public BlockQuoteElement(int start, int end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class CodeBlockElement implements MarkupElement.BlockLevelMarkupElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "bcode";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Code Block element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
*/
|
||||||
|
public CodeBlockElement(int start, int end) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class ListElement implements MarkupElement.MarkupChildElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "list";
|
||||||
|
public static final String ELEM_LI = "li";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
private final List<ListEntryElement> entries;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new List element.
|
||||||
|
*
|
||||||
|
* @param start start index of the list
|
||||||
|
* @param end end index of the list
|
||||||
|
* @param entries list entries
|
||||||
|
*/
|
||||||
|
public ListElement(int start, int end, List<ListEntryElement> entries) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.entries = Collections.unmodifiableList(entries);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all list entries.
|
||||||
|
*
|
||||||
|
* @return entries
|
||||||
|
*/
|
||||||
|
public List<ListEntryElement> getEntries() {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CharSequence toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
for (ListEntryElement li : getEntries()) {
|
||||||
|
xml.append(li.toXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ListEntryElement implements NamedElement {
|
||||||
|
|
||||||
|
private final int start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ListEntry element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
*/
|
||||||
|
public ListEntryElement(int start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the start index of this entry.
|
||||||
|
* @return start index
|
||||||
|
*/
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEM_LI;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.closeEmptyElement();
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,312 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||||
|
import org.jivesoftware.smack.packet.NamedElement;
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class MarkupElement implements ExtensionElement {
|
||||||
|
|
||||||
|
public static final String NAMESPACE = "urn:xmpp:markup:0";
|
||||||
|
public static final String ELEMENT = "markup";
|
||||||
|
|
||||||
|
private final List<MarkupChildElement> childElements;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new MarkupElement.
|
||||||
|
*
|
||||||
|
* @param childElements child elements.
|
||||||
|
*/
|
||||||
|
public MarkupElement(List<MarkupChildElement> childElements) {
|
||||||
|
this.childElements = Collections.unmodifiableList(childElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new Builder for Message Markup elements.
|
||||||
|
* @return builder.
|
||||||
|
*/
|
||||||
|
public static Builder getBuilder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of all child elements.
|
||||||
|
* @return children
|
||||||
|
*/
|
||||||
|
public List<MarkupChildElement> getChildElements() {
|
||||||
|
return childElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return NAMESPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder(this).rightAngleBracket();
|
||||||
|
|
||||||
|
for (MarkupChildElement child : getChildElements()) {
|
||||||
|
xml.append(child.toXML());
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
private final List<SpanElement> spans = new ArrayList<>();
|
||||||
|
private final List<BlockQuoteElement> quotes = new ArrayList<>();
|
||||||
|
private final List<CodeBlockElement> codes = new ArrayList<>();
|
||||||
|
private final List<ListElement> lists = new ArrayList<>();
|
||||||
|
|
||||||
|
private Builder() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as deleted.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setDeleted(int start, int end) {
|
||||||
|
return addSpan(start, end, Collections.singleton(SpanElement.SpanStyle.deleted));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as emphasized.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setEmphasis(int start, int end) {
|
||||||
|
return addSpan(start, end, Collections.singleton(SpanElement.SpanStyle.emphasis));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as inline code.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setCode(int start, int end) {
|
||||||
|
return addSpan(start, end, Collections.singleton(SpanElement.SpanStyle.code));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a span element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @param styles list of text styles for that span
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder addSpan(int start, int end, Set<SpanElement.SpanStyle> styles) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
for (SpanElement other : spans) {
|
||||||
|
if ((start >= other.getStart() && start <= other.getEnd()) ||
|
||||||
|
(end >= other.getStart() && end <= other.getEnd())) {
|
||||||
|
throw new IllegalArgumentException("Spans MUST NOT overlap each other.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spans.add(new SpanElement(start, end, styles));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as block quote.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setBlockQuote(int start, int end) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
for (BlockQuoteElement other : quotes) {
|
||||||
|
// 1 if out, 0 if on, -1 if in
|
||||||
|
Integer s = start;
|
||||||
|
Integer e = end;
|
||||||
|
int startPos = s.compareTo(other.getStart()) * s.compareTo(other.getEnd());
|
||||||
|
int endPos = e.compareTo(other.getStart()) * e.compareTo(other.getEnd());
|
||||||
|
int allowed = startPos * endPos;
|
||||||
|
|
||||||
|
if (allowed < 1) {
|
||||||
|
throw new IllegalArgumentException("BlockQuotes MUST NOT overlap each others boundaries");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quotes.add(new BlockQuoteElement(start, end));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark a section of a message as a code block.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder setCodeBlock(int start, int end) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
codes.add(new CodeBlockElement(start, end));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a list.
|
||||||
|
*
|
||||||
|
* @return list builder
|
||||||
|
*/
|
||||||
|
public Builder.ListBuilder beginList() {
|
||||||
|
return new Builder.ListBuilder(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ListBuilder {
|
||||||
|
private final Builder markup;
|
||||||
|
private final ArrayList<ListElement.ListEntryElement> entries = new ArrayList<>();
|
||||||
|
private int end = -1;
|
||||||
|
|
||||||
|
private ListBuilder(Builder markup) {
|
||||||
|
this.markup = markup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an entry to the list.
|
||||||
|
* The start index of an entry must correspond to the end index of the previous entry
|
||||||
|
* (if a previous entry exists.)
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @return list builder
|
||||||
|
*/
|
||||||
|
public Builder.ListBuilder addEntry(int start, int end) {
|
||||||
|
verifyStartEnd(start, end);
|
||||||
|
|
||||||
|
ListElement.ListEntryElement last = entries.size() == 0 ? null : entries.get(entries.size() - 1);
|
||||||
|
// Entries themselves do not store end values, that's why we store the last entries end value in this.end
|
||||||
|
if (last != null && start != this.end) {
|
||||||
|
throw new IllegalArgumentException("Next entries start must be equal to last entries end (" + this.end + ").");
|
||||||
|
}
|
||||||
|
entries.add(new ListElement.ListEntryElement(start));
|
||||||
|
this.end = end;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the list.
|
||||||
|
*
|
||||||
|
* @return builder
|
||||||
|
*/
|
||||||
|
public Builder endList() {
|
||||||
|
if (entries.size() > 0) {
|
||||||
|
ListElement.ListEntryElement first = entries.get(0);
|
||||||
|
ListElement list = new ListElement(first.getStart(), end, entries);
|
||||||
|
markup.lists.add(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return markup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a Message Markup element.
|
||||||
|
*
|
||||||
|
* @return extension element
|
||||||
|
*/
|
||||||
|
public MarkupElement build() {
|
||||||
|
List<MarkupElement.MarkupChildElement> children = new ArrayList<>();
|
||||||
|
children.addAll(spans);
|
||||||
|
children.addAll(quotes);
|
||||||
|
children.addAll(codes);
|
||||||
|
children.addAll(lists);
|
||||||
|
return new MarkupElement(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void verifyStartEnd(int start, int end) {
|
||||||
|
if (start >= end || start < 0) {
|
||||||
|
throw new IllegalArgumentException("Start value (" + start + ") MUST be greater equal than 0 " +
|
||||||
|
"and MUST be smaller than end value (" + end + ").");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for child elements.
|
||||||
|
*/
|
||||||
|
public interface MarkupChildElement extends NamedElement {
|
||||||
|
|
||||||
|
String ATTR_START = "start";
|
||||||
|
String ATTR_END = "end";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the start index of this element.
|
||||||
|
*
|
||||||
|
* @return start index
|
||||||
|
*/
|
||||||
|
int getStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the end index of this element.
|
||||||
|
*
|
||||||
|
* @return end index
|
||||||
|
*/
|
||||||
|
int getEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for block level child elements.
|
||||||
|
*/
|
||||||
|
public interface BlockLevelMarkupElement extends MarkupChildElement {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||||
|
|
||||||
|
public class SpanElement implements MarkupElement.MarkupChildElement {
|
||||||
|
|
||||||
|
public static final String ELEMENT = "span";
|
||||||
|
|
||||||
|
private final int start, end;
|
||||||
|
private final Set<SpanStyle> styles;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new Span element.
|
||||||
|
*
|
||||||
|
* @param start start index
|
||||||
|
* @param end end index
|
||||||
|
* @param styles list of styles that apply to this span
|
||||||
|
*/
|
||||||
|
public SpanElement(int start, int end, Set<SpanStyle> styles) {
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
this.styles = Collections.unmodifiableSet(styles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all styles of this span.
|
||||||
|
*
|
||||||
|
* @return styles
|
||||||
|
*/
|
||||||
|
public Set<SpanStyle> getStyles() {
|
||||||
|
return styles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String emphasis = "emphasis";
|
||||||
|
public static final String code = "code";
|
||||||
|
public static final String deleted = "deleted";
|
||||||
|
|
||||||
|
public enum SpanStyle {
|
||||||
|
emphasis,
|
||||||
|
code,
|
||||||
|
deleted
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getElementName() {
|
||||||
|
return ELEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XmlStringBuilder toXML() {
|
||||||
|
XmlStringBuilder xml = new XmlStringBuilder();
|
||||||
|
xml.halfOpenElement(this);
|
||||||
|
xml.attribute(ATTR_START, getStart());
|
||||||
|
xml.attribute(ATTR_END, getEnd());
|
||||||
|
xml.rightAngleBracket();
|
||||||
|
|
||||||
|
for (SpanStyle style : getStyles()) {
|
||||||
|
xml.halfOpenElement(style.toString()).closeEmptyElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
xml.closeElement(this);
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XEP-0394: Message Markup.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0394.html">XEP-0394: Message
|
||||||
|
* Markup</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.element;
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XEP-0394: Message Markup.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0394.html">XEP-0394: Message
|
||||||
|
* Markup</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup;
|
|
@ -0,0 +1,139 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.provider;
|
||||||
|
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.START_TAG;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.SmackException;
|
||||||
|
import org.jivesoftware.smack.provider.ExtensionElementProvider;
|
||||||
|
import org.jivesoftware.smack.util.ParserUtils;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.BlockQuoteElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.CodeBlockElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.ListElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.MarkupElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.SpanElement;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class MarkupElementProvider extends ExtensionElementProvider<MarkupElement> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MarkupElement parse(XmlPullParser parser, int initialDepth) throws Exception {
|
||||||
|
|
||||||
|
MarkupElement.Builder markup = MarkupElement.getBuilder();
|
||||||
|
|
||||||
|
int spanStart = -1, spanEnd = -1;
|
||||||
|
Set<SpanElement.SpanStyle> spanStyles = new HashSet<>();
|
||||||
|
|
||||||
|
int listStart = -1, listEnd = -1;
|
||||||
|
List<ListElement.ListEntryElement> lis = new ArrayList<>();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int tag = parser.next();
|
||||||
|
String name = parser.getName();
|
||||||
|
int start, end;
|
||||||
|
switch (tag) {
|
||||||
|
case START_TAG:
|
||||||
|
switch (name) {
|
||||||
|
case BlockQuoteElement.ELEMENT:
|
||||||
|
start = ParserUtils.getIntegerAttributeOrThrow(parser, BlockQuoteElement.ATTR_START,
|
||||||
|
"Message Markup BlockQuoteElement MUST contain a 'start' attribute.");
|
||||||
|
end = ParserUtils.getIntegerAttributeOrThrow(parser, BlockQuoteElement.ATTR_END,
|
||||||
|
"Message Markup BlockQuoteElement MUST contain a 'end' attribute.");
|
||||||
|
markup.setBlockQuote(start, end);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CodeBlockElement.ELEMENT:
|
||||||
|
start = ParserUtils.getIntegerAttributeOrThrow(parser, CodeBlockElement.ATTR_START,
|
||||||
|
"Message Markup CodeBlockElement MUST contain a 'start' attribute.");
|
||||||
|
end = ParserUtils.getIntegerAttributeOrThrow(parser, CodeBlockElement.ATTR_END,
|
||||||
|
"Message Markup CodeBlockElement MUST contain a 'end' attribute.");
|
||||||
|
markup.setCodeBlock(start, end);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.ELEMENT:
|
||||||
|
spanStyles = new HashSet<>();
|
||||||
|
spanStart = ParserUtils.getIntegerAttributeOrThrow(parser, SpanElement.ATTR_START,
|
||||||
|
"Message Markup SpanElement MUST contain a 'start' attribute.");
|
||||||
|
spanEnd = ParserUtils.getIntegerAttributeOrThrow(parser, SpanElement.ATTR_END,
|
||||||
|
"Message Markup SpanElement MUST contain a 'end' attribute.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.code:
|
||||||
|
spanStyles.add(SpanElement.SpanStyle.code);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.emphasis:
|
||||||
|
spanStyles.add(SpanElement.SpanStyle.emphasis);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SpanElement.deleted:
|
||||||
|
spanStyles.add(SpanElement.SpanStyle.deleted);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ListElement.ELEMENT:
|
||||||
|
lis = new ArrayList<>();
|
||||||
|
listStart = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_START,
|
||||||
|
"Message Markup ListElement MUST contain a 'start' attribute.");
|
||||||
|
listEnd = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_END,
|
||||||
|
"Message Markup ListElement MUST contain a 'end' attribute.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ListElement.ELEM_LI:
|
||||||
|
start = ParserUtils.getIntegerAttributeOrThrow(parser, ListElement.ATTR_START,
|
||||||
|
"Message Markup ListElement 'li' MUST contain a 'start' attribute.");
|
||||||
|
lis.add(new ListElement.ListEntryElement(start));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case END_TAG:
|
||||||
|
switch (name) {
|
||||||
|
case SpanElement.ELEMENT:
|
||||||
|
markup.addSpan(spanStart, spanEnd, spanStyles);
|
||||||
|
spanStart = -1; spanEnd = -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ListElement.ELEMENT:
|
||||||
|
MarkupElement.Builder.ListBuilder listBuilder = markup.beginList();
|
||||||
|
if (lis.size() > 0 && lis.get(0).getStart() != listStart) {
|
||||||
|
throw new SmackException("Error while parsing incoming MessageMarkup ListElement: " +
|
||||||
|
"'start' attribute of first 'li' element must equal 'start' attribute of list.");
|
||||||
|
}
|
||||||
|
for (int i = 0; i < lis.size(); i++) {
|
||||||
|
int elemStart = lis.get(i).getStart();
|
||||||
|
int elemEnd = i < lis.size() - 1 ? lis.get(i + 1).getStart() : listEnd;
|
||||||
|
listBuilder.addEntry(elemStart, elemEnd);
|
||||||
|
}
|
||||||
|
listBuilder.endList();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MarkupElement.ELEMENT:
|
||||||
|
return markup.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XEP-0394: Message Markup.
|
||||||
|
*
|
||||||
|
* @see <a href="http://xmpp.org/extensions/xep-0394.html">XEP-0394: Message
|
||||||
|
* Markup</a>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup.provider;
|
|
@ -296,4 +296,11 @@
|
||||||
<className>org.jivesoftware.smackx.eme.provider.ExplicitMessageEncryptionProvider</className>
|
<className>org.jivesoftware.smackx.eme.provider.ExplicitMessageEncryptionProvider</className>
|
||||||
</extensionProvider>
|
</extensionProvider>
|
||||||
|
|
||||||
|
<!-- XEP-0394: Message Markup -->
|
||||||
|
<extensionProvider>
|
||||||
|
<elementName>markup</elementName>
|
||||||
|
<namespace>urn:xmpp:markup:0</namespace>
|
||||||
|
<className>org.jivesoftware.smackx.message_markup.provider.MarkupElementProvider</className>
|
||||||
|
</extensionProvider>
|
||||||
|
|
||||||
</smackProviders>
|
</smackProviders>
|
||||||
|
|
|
@ -0,0 +1,227 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright © 2018 Paul Schaub
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.jivesoftware.smackx.message_markup;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.assertEquals;
|
||||||
|
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.jivesoftware.smack.test.util.SmackTestSuite;
|
||||||
|
import org.jivesoftware.smack.test.util.TestUtils;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.BlockQuoteElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.CodeBlockElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.ListElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.MarkupElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.element.SpanElement;
|
||||||
|
import org.jivesoftware.smackx.message_markup.provider.MarkupElementProvider;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
public class MessageMarkupTest extends SmackTestSuite {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void emphasisTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<span start='9' end='15'>" +
|
||||||
|
"<emphasis/>" +
|
||||||
|
"</span>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setEmphasis(9, 15);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
SpanElement spanElement = (SpanElement) children.get(0);
|
||||||
|
assertEquals(9, spanElement.getStart());
|
||||||
|
assertEquals(15, spanElement.getEnd());
|
||||||
|
assertEquals(1, spanElement.getStyles().size());
|
||||||
|
assertEquals(SpanElement.SpanStyle.emphasis, spanElement.getStyles().iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void codeTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<span start='9' end='15'>" +
|
||||||
|
"<code/>" +
|
||||||
|
"</span>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setCode(9, 15);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
SpanElement spanElement = (SpanElement) children.get(0);
|
||||||
|
assertEquals(9, spanElement.getStart());
|
||||||
|
assertEquals(15, spanElement.getEnd());
|
||||||
|
assertEquals(1, spanElement.getStyles().size());
|
||||||
|
assertEquals(SpanElement.SpanStyle.code, spanElement.getStyles().iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void deletedTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<span start='9' end='15'>" +
|
||||||
|
"<deleted/>" +
|
||||||
|
"</span>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setDeleted(9, 15);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
SpanElement spanElement = (SpanElement) children.get(0);
|
||||||
|
assertEquals(9, spanElement.getStart());
|
||||||
|
assertEquals(15, spanElement.getEnd());
|
||||||
|
assertEquals(1, spanElement.getStyles().size());
|
||||||
|
assertEquals(SpanElement.SpanStyle.deleted, spanElement.getStyles().iterator().next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void wrongStartEndTest() {
|
||||||
|
MarkupElement.getBuilder().setEmphasis(12, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void overlappingSpansTest() {
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setEmphasis(0, 10);
|
||||||
|
m.setDeleted(5, 15);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void codeBlockTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<bcode start='23' end='48'/>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setCodeBlock(23, 48);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
CodeBlockElement codeBlock = (CodeBlockElement) children.get(0);
|
||||||
|
assertEquals(23, codeBlock.getStart());
|
||||||
|
assertEquals(48, codeBlock.getEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void listTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<list start='31' end='89'>" +
|
||||||
|
"<li start='31'/>" +
|
||||||
|
"<li start='47'/>" +
|
||||||
|
"<li start='61'/>" +
|
||||||
|
"<li start='69'/>" +
|
||||||
|
"</list>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m = m.beginList()
|
||||||
|
.addEntry(31, 47)
|
||||||
|
.addEntry(47, 61)
|
||||||
|
.addEntry(61, 69)
|
||||||
|
.addEntry(69, 89)
|
||||||
|
.endList();
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
ListElement list = (ListElement) children.get(0);
|
||||||
|
assertEquals(31, list.getStart());
|
||||||
|
assertEquals(89, list.getEnd());
|
||||||
|
assertEquals(4, list.getEntries().size());
|
||||||
|
assertEquals(list.getStart(), list.getEntries().get(0).getStart());
|
||||||
|
assertEquals(47, list.getEntries().get(1).getStart());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void listWrongSecondEntryTest() {
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.beginList().addEntry(0,1).addEntry(3,4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void blockQuoteTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<bquote start='9' end='32'/>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setBlockQuote(9 ,32);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(1, children.size());
|
||||||
|
|
||||||
|
BlockQuoteElement quote = (BlockQuoteElement) children.get(0);
|
||||||
|
assertEquals(9, quote.getStart());
|
||||||
|
assertEquals(32, quote.getEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void nestedBlockQuoteTest() throws Exception {
|
||||||
|
String xml =
|
||||||
|
"<markup xmlns='urn:xmpp:markup:0'>" +
|
||||||
|
"<bquote start='0' end='57'/>" +
|
||||||
|
"<bquote start='11' end='34'/>" +
|
||||||
|
"</markup>";
|
||||||
|
MarkupElement.Builder m = MarkupElement.getBuilder();
|
||||||
|
m.setBlockQuote(0, 57);
|
||||||
|
m.setBlockQuote(11, 34);
|
||||||
|
assertXMLEqual(xml, m.build().toXML().toString());
|
||||||
|
|
||||||
|
XmlPullParser parser = TestUtils.getParser(xml);
|
||||||
|
MarkupElement parsed = new MarkupElementProvider().parse(parser);
|
||||||
|
List<MarkupElement.MarkupChildElement> children = parsed.getChildElements();
|
||||||
|
assertEquals(2, children.size());
|
||||||
|
|
||||||
|
BlockQuoteElement q1 = (BlockQuoteElement) children.get(0);
|
||||||
|
BlockQuoteElement q2 = (BlockQuoteElement) children.get(1);
|
||||||
|
|
||||||
|
assertEquals(0, q1.getStart());
|
||||||
|
assertEquals(57, q1.getEnd());
|
||||||
|
|
||||||
|
assertEquals(11, q2.getStart());
|
||||||
|
assertEquals(34, q2.getEnd());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue