1

我想知道在检票口中是否有可能发生这样的事情:

<span wicket:id="label"><a wicket:id="link"></a></span>

链接可以在标签的所需位置呈现(无需拆分)。

例如,考虑以下标签:“[LINK]roses[/LINK] are red” 如果“The”和“are red”是动态的,我们必须使用多个标签:

<span wicket:id="firstPartLabel"/><a wicket:id="link"/><span wicket:id="lastPartLabel">

这很丑陋,我们不能插入链接,因此考虑到标签 The ${link} are red 并用适当的链接替换占位符?

谢谢

4

4 回答 4

0

如果您想要做的是类似于 Twitter 的主题标签/用户名链接(处理纯文本并添加到特殊段的链接),您可以扩展 Label 来做到这一点。只需在文本中搜索特殊单词(这里我使用了正则表达式模式,但您可以使用任何其他方法)并将它们替换为链接的 HTML。

在本例中,isInternalRef创建一个指向 Ajax 行为的链接。它还可用于创建指向资源、页面和其他类型组件的链接(有些处理直接链接,有些不处理)。

这个类是一个非常简单的例子,它并不打算支持所有的 Twitter 语法。

public class TweetLabel extends Label {

    private static final Pattern USERNAME_HASHTAG_PATTERN = Pattern.compile("\\B([@#*])([a-zA-Z0-9_]+)", Pattern.CASE_INSENSITIVE);

    private transient CharSequence body;

    public TweetLabel(String id) {
        super(id);
    }
    public TweetLabel(String id, String label) {
        super(id, label);
    }
    public TweetLabel(String id, Serializable label) {
        super(id, label);
    }
    public TweetLabel(String id, IModel<?> model) {
        super(id, model);
    }

    protected void onLinkClicked(AjaxRequestTarget target, String word) {
        target.appendJavaScript("alert('You clicked on \"" + JavaScriptUtils.escapeQuotes(word) + "\", and the server knows...');");
    }

    @Override
    protected void onConfigure() {
        super.onConfigure();

        // process text here, because we can add behaviors here, but not at onComponentTagBody()
        body = processText(getDefaultModelObjectAsString());
    }

    @Override
    public void onComponentTagBody(MarkupStream markupStream, ComponentTag openTag) {
        replaceComponentTagBody(markupStream, openTag, body);
    }

    /** 
     * based on Matcher.replaceAll()
     */
    private CharSequence processText(String text) {
        Matcher m = USERNAME_HASHTAG_PATTERN.matcher(text);
        boolean result = m.find();
        if (result) {
            StringBuffer sb = new StringBuffer();
            do {
                final String replacement = getLinkedTextAndAddBehavior(text, m.start(), m.end());
                m.appendReplacement(sb, replacement);
                result = m.find();
            } while (result);
            m.appendTail(sb);
            return sb;
        }
        return text;
    }

    private String getLinkedTextAndAddBehavior(String fullText, int start, int end) {

        final String matchedString = fullText.substring(start, end);
        final int length = matchedString.length();
        final String prefix = matchedString.substring(0, 1);
        final String identifier = matchedString.substring(1, length);
        final boolean isUsername = prefix.equals("@");
        final boolean isHashtag = prefix.equals("#") && (start == 0 || fullText.charAt(start - 1) != '&');
        final boolean isInternalRef = prefix.equals("*");

        final String replacement;
        if (isUsername) {

            final String url = "https://twitter.com/" + identifier;
            replacement = "<a href='" + url + "'>" + matchedString + "</a>";

        } else if (isHashtag) {

            final String url = "https://twitter.com/search?src=hash&q=" + UrlEncoder.QUERY_INSTANCE.encode(matchedString, "UTF-8");
            replacement = "<a href='" + url + "'>" + matchedString + "</a>";

        } else if (isInternalRef) {

            final LinkedWordBehavior behavior = getOrAddBehavior(new LinkedWordBehavior(identifier));
            final String rawFunction = behavior.getCallbackScript().toString();
            replacement = String.format("<a href='#' onclick='%s;return false;'>%s</a>", rawFunction, matchedString);

        } else {
            replacement = matchedString;
        }

        return replacement;
    }

    /**
     * Verify if the behavior was already added, add if not.
     */
    private LinkedWordBehavior getOrAddBehavior(LinkedWordBehavior behavior) {
        final List<LinkedWordBehavior> behaviors = getBehaviors(LinkedWordBehavior.class);
        final int index = behaviors.indexOf(behavior);
        if (index > -1) {
            return behaviors.get(index);
        } else {
            add(behavior);
            return behavior;
        }
    }

    private final class LinkedWordBehavior extends AbstractDefaultAjaxBehavior {
        private final String word;
        public LinkedWordBehavior(String word) {
            this.word = word;
        }
        @Override
        protected void respond(AjaxRequestTarget target) {
            final String word = TweetLabel.this.getRequest().getRequestParameters().getParameterValue("word").toString();
            if (!Strings.isEmpty(word)) {
                TweetLabel.this.onLinkClicked(target, word);
            }
        }
        protected void updateAjaxAttributes(AjaxRequestAttributes attributes) {
            super.updateAjaxAttributes(attributes);
            attributes.getExtraParameters().put("word", word);
        }
        @Override
        public int hashCode() {
            return word.hashCode();
        }
        @Override
        public boolean equals(Object obj) {
            return word.equals(((LinkedWordBehavior) obj).word);
        }
    }
}

更新更改了示例以处理带有行为的 ajax 请求。还有其他方法可以做到这一点。例如,您可以使用单一行为来处理所有链接,或使用资源,但这种方式对我来说看起来更干净。

于 2013-07-06T12:03:30.367 回答
0

我解决了这个问题,创建了一个名为 LinkLabel 的自定义面板。该组件仍然对两个标签使用“硬编码标记”,但至少它可以工作。

你可以这样使用它:

LinkLabel myLabel = new LinkLabel("description",
        "First ${link} second", "my link", new ILinkListener() {

            private static final long serialVersionUID = 1L;

            @Override
            public void onLinkClicked() {
                // Your desired onClick action
            }
        });

该组件的java代码如下:

public class LinkLabel extends Panel {

    private static final long serialVersionUID = 1L;

    public LinkLabel(String id, String model, String linkName,
            ILinkListener linkListener) {
        super(id);
        setRenderBodyOnly(true);
        String[] split = model.split("\\$\\{link\\}");
        if (split.length == 2) {
            Label first = new Label("first", split[0]);
            Label second = new Label("second", split[1]);

            add(first);
            add(second);
            add(generateLink(linkListener, linkName));
        } else if (split.length == 1) {
            Label first = new Label("first", split[0]);
            Label second = new Label("second");
            second.setVisible(false);
            add(first);
            add(second);
            add(generateLink(linkListener, linkName));
        } else {
            throw new UnsupportedOperationException(
                    "LinkLabel needs the ${link} placeholder!");
        }
    }

    private Link<?> generateLink(final ILinkListener linkListener,
            String linkName) {
        Label linkLabel = new Label("linkLabel", linkName);
        Link<String> link = new Link<String>("link") {
            private static final long serialVersionUID = 1L;

            @Override
            public void onClick() {
                linkListener.onLinkClicked();
            }
        };
        link.add(linkLabel);
        return link;
    }
}

组件的标记:

<wicket:panel>
    <span wicket:id="first"></span>
    <a wicket:id="link"><span wicket:id="linkLabel"></span></a>
    <span wicket:id="second"></span>
</wicket:panel>
于 2013-07-08T14:22:38.033 回答
0

一种简单String的方法是使用标准<a href=""> </a>标签将链接构建为您自己。然后,您的 Java 代码可以将其String作为Label带有属性的 a 提供.setEscapeModelStrings(false)。您的 html 标记是标准的 Wicket 标签。

在标记中,我建议在 Lorem ipsum 文本下划线(在 Wicket 替换标签后将不会看到)。当您设计标记时,这有助于提醒您此标签将成为一个链接。

示例标记:

<span wicket:id="mylabel"><u>Lorem ipsum dolor</u></span>

示例 Java:

    this.createLink("mylabel", "The", "ROSES", "are red", "https://testurl.com");
}

private Void createLink(String label, String textBefore, String textLink, String textAfter, String url)
{
    String htmlLink = "<a href='" + url + "'>" + textLink + "</a>";
    String labelText = textBefore + htmlLink + textAfter;
    this.add(new Label(label, labelText).setEscapeModelStrings(false));
}
于 2018-09-15T12:43:18.847 回答