mirror of https://github.com/kurisufriend/Clover
parent
5fc8c7b0d7
commit
10ed72775e
@ -0,0 +1,128 @@ |
|||||||
|
/* |
||||||
|
* Clover - 4chan browser https://github.com/Floens/Clover/
|
||||||
|
* Copyright (C) 2014 Floens |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/ |
||||||
|
package org.floens.chan.core.site.common; |
||||||
|
|
||||||
|
import android.text.SpannableString; |
||||||
|
|
||||||
|
import org.floens.chan.core.model.Post; |
||||||
|
import org.floens.chan.core.model.PostLinkable; |
||||||
|
import org.floens.chan.ui.theme.Theme; |
||||||
|
import org.jsoup.helper.StringUtil; |
||||||
|
import org.jsoup.nodes.Element; |
||||||
|
import org.jsoup.nodes.Node; |
||||||
|
import org.jsoup.nodes.TextNode; |
||||||
|
import org.jsoup.select.NodeTraversor; |
||||||
|
import org.jsoup.select.NodeVisitor; |
||||||
|
import org.nibor.autolink.LinkExtractor; |
||||||
|
import org.nibor.autolink.LinkSpan; |
||||||
|
import org.nibor.autolink.LinkType; |
||||||
|
|
||||||
|
import java.util.EnumSet; |
||||||
|
|
||||||
|
public class ChanParserHelper { |
||||||
|
private static final LinkExtractor LINK_EXTRACTOR = LinkExtractor.builder() |
||||||
|
.linkTypes(EnumSet.of(LinkType.URL)) |
||||||
|
.build(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Detect links in the given spannable, and create PostLinkables with Type.LINK for the |
||||||
|
* links found onto the spannable. |
||||||
|
* <p> |
||||||
|
* The links are detected with the autolink-java library. |
||||||
|
* |
||||||
|
* @param theme The theme to style the links with |
||||||
|
* @param post The post where the linkables get added to. |
||||||
|
* @param text Text to find links in |
||||||
|
* @param spannable Spannable to set the spans on. |
||||||
|
*/ |
||||||
|
public static void detectLinks(Theme theme, Post.Builder post, String text, SpannableString spannable) { |
||||||
|
final Iterable<LinkSpan> links = LINK_EXTRACTOR.extractLinks(text); |
||||||
|
for (final LinkSpan link : links) { |
||||||
|
final String linkText = text.substring(link.getBeginIndex(), link.getEndIndex()); |
||||||
|
final PostLinkable pl = new PostLinkable(theme, linkText, linkText, PostLinkable.Type.LINK); |
||||||
|
spannable.setSpan(pl, link.getBeginIndex(), link.getEndIndex(), 0); |
||||||
|
post.addLinkable(pl); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Below code taken from org.jsoup.nodes.Element.text(), but it preserves <br>
|
||||||
|
public static String getNodeTextPreservingLineBreaks(Element node) { |
||||||
|
final StringBuilder accum = new StringBuilder(); |
||||||
|
new NodeTraversor(new NodeVisitor() { |
||||||
|
public void head(Node node, int depth) { |
||||||
|
if (node instanceof TextNode) { |
||||||
|
TextNode textNode = (TextNode) node; |
||||||
|
appendNormalisedText(accum, textNode); |
||||||
|
} else if (node instanceof Element) { |
||||||
|
Element element = (Element) node; |
||||||
|
if (accum.length() > 0 && |
||||||
|
element.isBlock() && |
||||||
|
!lastCharIsWhitespace(accum)) |
||||||
|
accum.append(" "); |
||||||
|
|
||||||
|
if (element.tag().getName().equals("br")) { |
||||||
|
accum.append("\n"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void tail(Node node, int depth) { |
||||||
|
} |
||||||
|
}).traverse(node); |
||||||
|
return accum.toString().trim(); |
||||||
|
} |
||||||
|
|
||||||
|
// Copied from org.jsoup.nodes.Element.text()
|
||||||
|
private static boolean lastCharIsWhitespace(StringBuilder sb) { |
||||||
|
return sb.length() != 0 && sb.charAt(sb.length() - 1) == ' '; |
||||||
|
} |
||||||
|
|
||||||
|
// Copied from org.jsoup.nodes.Element.text()
|
||||||
|
private static void appendNormalisedText(StringBuilder accum, TextNode textNode) { |
||||||
|
String text = textNode.getWholeText(); |
||||||
|
|
||||||
|
if (!preserveWhitespace(textNode.parent())) { |
||||||
|
text = normaliseWhitespace(text); |
||||||
|
if (lastCharIsWhitespace(accum)) |
||||||
|
text = stripLeadingWhitespace(text); |
||||||
|
} |
||||||
|
accum.append(text); |
||||||
|
} |
||||||
|
|
||||||
|
// Copied from org.jsoup.nodes.Element.text()
|
||||||
|
private static String normaliseWhitespace(String text) { |
||||||
|
text = StringUtil.normaliseWhitespace(text); |
||||||
|
return text; |
||||||
|
} |
||||||
|
|
||||||
|
// Copied from org.jsoup.nodes.Element.text()
|
||||||
|
private static String stripLeadingWhitespace(String text) { |
||||||
|
return text.replaceFirst("^\\s+", ""); |
||||||
|
} |
||||||
|
|
||||||
|
// Copied from org.jsoup.nodes.Element.text()
|
||||||
|
private static boolean preserveWhitespace(Node node) { |
||||||
|
// looks only at this element and one level up, to prevent recursion & needless stack searches
|
||||||
|
if (node != null && node instanceof Element) { |
||||||
|
Element element = (Element) node; |
||||||
|
return element.tag().preserveWhitespace() || |
||||||
|
element.parent() != null && element.parent().tag().preserveWhitespace(); |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue