我需要一个输入字段,能够在标记名中包含带空格的标记,如下所示:
我知道<p:autoComplete multiple="true">
支持使用标记,但它使用空格来分隔标记:
我想在标记名中包含空格,然后使用; 或 Enter 进入下一个标记。如何创建新的自定义组件,或为此自定义<p:autoComplete>
?我使用的是JSF 2.2和PrimeFaces 3.2。
答案 0 :(得分:1)
为什么不重写/修改它的JavaScript函数(在autocomplete.js中)?
代码&amp;感兴趣的功能:
<强> bindStaticEvents 强>
bindStaticEvents: function() {
var $this = this;
this.bindKeyEvents();
this.dropdown.mouseover(function() {
$(this).addClass('ui-state-hover');
}).mouseout(function() {
$(this).removeClass('ui-state-hover');
}).mousedown(function() {
if($this.active) {
$(this).addClass('ui-state-active');
}
}).mouseup(function() {
if($this.active) {
$(this).removeClass('ui-state-active');
$this.search('');
$this.input.focus();
}
}).focus(function() {
$(this).addClass('ui-state-focus');
}).blur(function() {
$(this).removeClass('ui-state-focus');
}).keydown(function(e) {
var keyCode = $.ui.keyCode,
key = e.which;
if(key === keyCode.SPACE || key === keyCode.ENTER || key === keyCode.NUMPAD_ENTER) {
$(this).addClass('ui-state-active');
}
}).keyup(function(e) {
var keyCode = $.ui.keyCode,
key = e.which;
if(key === keyCode.SPACE || key === keyCode.ENTER || key === keyCode.NUMPAD_ENTER) {
$(this).removeClass('ui-state-active');
$this.search('');
$this.input.focus();
e.preventDefault();
e.stopPropagation();
}
});
bindKeyEvents
bindKeyEvents: function() {
var $this = this;
this.currentText = this.input.val();
this.previousText = this.input.val();
//bind keyup handler
this.input.keyup(function(e) {
var keyCode = $.ui.keyCode,
key = e.which,
shouldSearch = true;
$this.previousText = $this.currentText;
$this.currentText = this.value;
// Cancel a possible long running search when selecting an entry via enter
if (key === keyCode.ENTER || key === keyCode.NUMPAD_ENTER) {
if ($this.timeout) {
clearTimeout($this.timeout);
}
shouldSearch = false;
}
else if (key === keyCode.ESCAPE) {
$this.hide();
shouldSearch = false;
}
else if ((e.ctrlKey && key === 65) // ctrl+a
|| (e.ctrlKey && key === 67) // ctrl+c
|| key === keyCode.LEFT
|| key === keyCode.RIGHT
|| key === keyCode.TAB
|| key === 16 // keyCode.SHIFT
|| key === keyCode.HOME
|| key === keyCode.END
|| key === 18 // keyCode.ALT
|| key === 17 // keyCode.CONTROL
|| (key >= 112 && key <= 123)) { // F1-F12
shouldSearch = false;
}
else if(key === keyCode.UP || key === keyCode.DOWN) {
if($this.panel.is(':visible')) {
var highlightedItem = $this.items.filter('.ui-state-highlight');
if(highlightedItem.length) {
$this.displayAriaStatus(highlightedItem.data('item-label'));
}
}
shouldSearch = false;
}
else if($this.cfg.pojo && !$this.cfg.multiple && ($this.previousText !== $this.currentText)) {
$this.hinput.val($(this).val());
}
if(shouldSearch) {
var value = $this.input.val();
if(!value.length) {
$this.hide();
}
if(value.length >= $this.cfg.minLength) {
//Cancel the search request if user types within the timeout
if($this.timeout) {
clearTimeout($this.timeout);
}
var delay = $this.cfg.delay;
if (value != '' && (key == keyCode.BACKSPACE || key == keyCode.DELETE)) {
delay = $this.cfg.deletionDelay;
}
$this.timeout = setTimeout(function() {
$this.search(value);
}, delay);
}
}
}).keydown(function(e) {
var keyCode = $.ui.keyCode;
if($this.panel.is(':visible')) {
var highlightedItem = $this.items.filter('.ui-state-highlight');
switch(e.which) {
case keyCode.UP:
var prev = highlightedItem.length == 0 ? $this.items.eq(0) : highlightedItem.prevAll('.ui-autocomplete-item:first');
if(prev.length == 1) {
highlightedItem.removeClass('ui-state-highlight');
prev.addClass('ui-state-highlight');
if($this.cfg.scrollHeight) {
PrimeFaces.scrollInView($this.panel, prev);
}
if($this.cfg.itemtip) {
$this.showItemtip(prev);
}
}
e.preventDefault();
break;
case keyCode.DOWN:
var next = highlightedItem.length == 0 ? $this.items.eq(0) : highlightedItem.nextAll('.ui-autocomplete-item:first');
if(next.length == 1) {
highlightedItem.removeClass('ui-state-highlight');
next.addClass('ui-state-highlight');
if($this.cfg.scrollHeight) {
PrimeFaces.scrollInView($this.panel, next);
}
if($this.cfg.itemtip) {
$this.showItemtip(next);
}
}
e.preventDefault();
break;
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
highlightedItem.click();
e.preventDefault();
e.stopPropagation();
break;
case 18: //keyCode.ALT:
case 224:
break;
case keyCode.TAB:
highlightedItem.trigger('click');
$this.hide();
break;
}
}
else if (e.which == keyCode.TAB) {
// clear pending search before leaving the field
if ($this.timeout) {
clearTimeout($this.timeout);
}
}
});
},
<强> bindDynamicEvents 强>
bindDynamicEvents: function() {
var $this = this;
//visuals and click handler for items
this.items.bind('mouseover', function() {
var item = $(this);
if(!item.hasClass('ui-state-highlight')) {
$this.items.filter('.ui-state-highlight').removeClass('ui-state-highlight');
item.addClass('ui-state-highlight');
if($this.cfg.itemtip) {
$this.showItemtip(item);
}
}
})
.bind('click', function(event) {
var item = $(this),
itemValue = item.attr('data-item-value');
if($this.cfg.multiple) {
var itemDisplayMarkup = '<li data-token-value="' + item.attr('data-item-value') + '"class="ui-autocomplete-token ui-state-active ui-corner-all ui-helper-hidden">';
itemDisplayMarkup += '<span class="ui-autocomplete-token-icon ui-icon ui-icon-close" />';
itemDisplayMarkup += '<span class="ui-autocomplete-token-label">' + item.attr('data-item-label') + '</span></li>';
$this.inputContainer.before(itemDisplayMarkup);
$this.multiItemContainer.children('.ui-helper-hidden').fadeIn();
$this.input.val('').focus();
$this.hinput.append('<option value="' + itemValue + '" selected="selected"></option>');
}
else {
$this.input.val(item.attr('data-item-label')).focus();
this.currentText = $this.input.val();
this.previousText = $this.input.val();
if($this.cfg.pojo) {
$this.hinput.val(itemValue);
}
}
$this.invokeItemSelectBehavior(event, itemValue);
$this.hide();
});
},
建议:将key === keyCode.SPACE
替换为key === 188
(这是;
的代码)
注意:它可能会产生一些副作用,尤其是如果您在其他地方使用自动填充功能并且有所不同......
答案 1 :(得分:1)
看一下这个jquery plugin,它允许在可以允许空格的标签周围进行自定义(参见example page)。
您希望使用h:input创建复合组件,然后将jquery插件应用于它。这将为您提供类似于stackoverflow中语言标记的内容。
复合组件将聚合tagit使用javascript生成的隐藏输入,并设置h:inputHidden组件的值。像这样:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:cc="http://java.sun.com/jsf/composite"
xmlns:ui="http://java.sun.com/jsf/facelets">
<cc:interface shortDescription="TagIt wrapper">
<cc:attribute name="val" type="java.lang.String" required="true" shortDescription="value" />
</cc:interface>
<cc:implementation>
<h:outputStylesheet library="cui" name="jquery.tagit.css" target="head" />
<h:outputStylesheet library="cui" name="tagit.ui-zendesk.css" target="head" />
<h:outputScript library="primefaces" name="jquery/jquery.js" target="head" />
<h:outputScript library="cui" name="jquery-ui.min.js" target="head" />
<h:outputScript library="cui" name="tag-it.min.js" target="head" />
<h:outputScript>
$(function() {
//Activate the tagit plugin with the allow spaces option.
//we insert the clientId to insure uniqueness of ids in case the component
//was used multiple times on the same page. We must escape JSF's column
//separator since it's considered a special character for jQuery
var tagId = ("#" + "#{cc.clientId}:myTags".replace(/:/g, "\\:"));
$(tagId).tagit({allowSpaces: true});
//find the input element generated by the plugin and whenever it loses focus,
//update the hidden input with the values of all the tags separated by semi-columns
//The hidden input is wired to the 'val' attribute and will feed the value to the backing bean
$("input[type='text'].ui-widget-content").blur(function() {
var allTags = "";
$('.tagit-hidden-field').each(function() {
allTags += $(this).val() + ";"
});
var hiddenInputId = ("#" + "#{cc.clientId}:tagValue".replace(/:/g, "\\:"));
$(hiddenInputId).val(allTags);
});
});
</h:outputScript>
<h:inputHidden id="tagValue" value="#{cc.attrs.val}"/>
<p>Hit Enter or Comma to separate tags</p>
<ul id="#{cc.clientId}:myTags">
</ul>
</cc:implementation>
然后你会在页面上使用它:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:cui="http://java.sun.com/jsf/composite/cui">
<h:head></h:head>
<h:body>
<h:form id="form">
<cui:tagit val="#{page1.tags}" />
<h:commandButton value="Submit">
<f:ajax execute="@form" render="output"/>
</h:commandButton>
</h:form>
</h:body>
</html>