diff --git a/gradleResources/staticResources/css/ext/bootstrap-tagsinput.css b/gradleResources/staticResources/css/ext/bootstrap-tagsinput.css index 6c4445374..7fced3009 100755 --- a/gradleResources/staticResources/css/ext/bootstrap-tagsinput.css +++ b/gradleResources/staticResources/css/ext/bootstrap-tagsinput.css @@ -1,5 +1,5 @@ /* - * bootstrap-tagsinput v0.7.2 + * bootstrap-tagsinput v0.8.0 * */ @@ -44,22 +44,17 @@ margin-right: 2px; color: white; } -.bootstrap-tagsinput .tag [data-role='remove'] { +.bootstrap-tagsinput .tag [data-role="remove"] { margin-left: 8px; cursor: pointer; } -.bootstrap-tagsinput .tag [data-role='remove']:after { - content: 'x'; +.bootstrap-tagsinput .tag [data-role="remove"]:after { + content: "x"; padding: 0px 2px; } -.bootstrap-tagsinput .tag [data-role='remove']:hover { +.bootstrap-tagsinput .tag [data-role="remove"]:hover { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); } -.bootstrap-tagsinput .tag [data-role='remove']:hover:active { +.bootstrap-tagsinput .tag [data-role="remove"]:hover:active { box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125); } - -.bootstrap-tagsinput .twitter-typeahead { - position: absolute !important; - width: auto; -} diff --git a/gradleResources/staticResources/css/ext/input-tags.css b/gradleResources/staticResources/css/ext/input-tags.css index ffb4d4eb8..b72dc8214 100644 --- a/gradleResources/staticResources/css/ext/input-tags.css +++ b/gradleResources/staticResources/css/ext/input-tags.css @@ -6,7 +6,9 @@ .bootstrap-tagsinput .twitter-typeahead { width: auto; float: none; - position: relative !important; + position: absolute !important; + /* solution for #721 */ + width: auto; } .bootstrap-tagsinput .twitter-typeahead .tt-menu { diff --git a/gradleResources/staticResources/js/bootstrap-tagsinput.min.js b/gradleResources/staticResources/js/bootstrap-tagsinput.min.js index 3203f0314..044f4472e 100755 --- a/gradleResources/staticResources/js/bootstrap-tagsinput.min.js +++ b/gradleResources/staticResources/js/bootstrap-tagsinput.min.js @@ -1,7 +1,7 @@ /* - * bootstrap-tagsinput v0.7.2 + * bootstrap-tagsinput v0.8.0 * */ -!function(g){"use strict";var o={tagClass:function(t){return"label label-info"},focusClass:"focus",itemValue:function(t){return t?t.toString():t},itemText:function(t){return this.itemValue(t)},itemTitle:function(t){return null},freeInput:!0,addOnBlur:!0,maxTags:void 0,maxChars:void 0,confirmKeys:[13,44],delimiter:",",delimiterRegex:null,cancelConfirmKeysOnEmpty:!1,onTagExists:function(t,e){e.hide().fadeIn()},trimValue:!1,allowDuplicates:!1};function r(t,e){this.isInit=!0,this.itemsArray=[];var n=g(t.cloneNode());n.removeAttr("data-role"),n.val(""),this.$element=g(t),this.$element.hide(),this.isSelect="SELECT"===t.tagName,this.multiple=this.isSelect&&t.hasAttribute("multiple"),this.objectItems=e&&e.itemValue,this.placeholderText=t.hasAttribute("placeholder")?this.$element.attr("placeholder"):"",this.inputSize=Math.max(1,this.placeholderText.length),this.$container=g('
');var i=t.className.split(/\s+/),a=this.$container,o=["col-","form-control","offset-","visible-","hidden-"];i.forEach(function(e){e&&o.forEach(function(t){e.startsWith(t)&&(a.addClass(e),n.removeClass(e))})}),this.$element.removeAttr("id"),this.$input=n.appendTo(this.$container),this.$element.before(this.$container),this.build(e),this.isInit=!1}function s(t,e){if("function"!=typeof t[e]){var n=t[e];t[e]=function(t){return t[n]}}}function u(t,e){if("function"!=typeof t[e]){var n=t[e];t[e]=function(){return n}}}r.prototype={constructor:r,add:function(t,e,n){var i=this;if(!(i.options.maxTags&&i.itemsArray.length>=i.options.maxTags)&&(!1===t||t)){if("string"==typeof t&&i.options.trimValue&&(t=g.trim(t)),"object"==typeof t&&!i.objectItems)throw"Can't add objects when itemValue option is not set";if(!t.toString().match(/^\s*$/)){if(i.isSelect&&!i.multiple&&0+ * Show the words of the input text as tags (similar to price tags in the supermarket). You can select one or + * more tags. The list is sent to the backend bean as a comma-separated list. + *
* Usually this method is called internally by the JSF engine. + * + * @param _tags */ + @Override public void setTags(boolean _tags) { if (_tags) { addTagsResources(); @@ -159,8 +173,11 @@ public void setTags(boolean _tags) { } /** - * Activates the type-ahead aka autocomplete function. The list of values has to be defined in typeahead-values.
+ * Activates the type-ahead aka autocomplete function. The list of values has to be defined in typeahead-values. + *
* Usually this method is called internally by the JSF engine. + * + * @param _typeahead */ @Override public void setTypeahead(boolean _typeahead) { @@ -175,37 +192,39 @@ public void setTypeaheadValues(Object _typeaheadValues) { setTypeahead(true); super.setTypeaheadValues(_typeaheadValues); } - - /** - * Returns input mask. - * - * @return Input mask. - */ + + /** + * Returns input mask. + * + * @return Input mask. + */ + @Override public String getMask() { return (String) getStateHelper().eval(PropertyKeys.mask); } - /** - * Sets input mask and triggers JavaScript to be loaded. - * - * @param mask Input mask to set. - */ + /** + * Sets input mask and triggers JavaScript to be loaded. + * + * @param mask Input mask to set. + */ + @Override public void setMask(String mask) { if (mask != null && !mask.isEmpty()) { addInputmaskResources(); } - getStateHelper().put(PropertyKeys.mask, mask); + getStateHelper().put(PropertyKeys.mask, mask); } - + private void addInputmaskResources() { - AddResourcesListener.addResourceToHeadButAfterJQuery(C.BSF_LIBRARY, "js/jquery.inputmask.bundle.min.js"); + AddResourcesListener.addResourceToHeadButAfterJQuery(C.BSF_LIBRARY, "js/jquery.inputmask.bundle.min.js"); } private void addTypeaheadResources() { AddResourcesListener.addResourceToHeadButAfterJQuery(C.BSF_LIBRARY, "js/typeahead.js"); AddResourcesListener.addExtCSSResource("typeahead.css"); } - + private void addTagsResources() { AddResourcesListener.addResourceToHeadButAfterJQuery(C.BSF_LIBRARY, "js/bootstrap-tagsinput.min.js"); AddResourcesListener.addExtCSSResource("bootstrap-tagsinput.css"); diff --git a/src/main/java/net/bootsfaces/component/inputText/InputTextBeanInfo.java b/src/main/java/net/bootsfaces/component/inputText/InputTextBeanInfo.java index ff2f699a8..bb8c66505 100644 --- a/src/main/java/net/bootsfaces/component/inputText/InputTextBeanInfo.java +++ b/src/main/java/net/bootsfaces/component/inputText/InputTextBeanInfo.java @@ -3,17 +3,19 @@ import net.bootsfaces.beans.BsfBeanInfo; /** - * BeanInfo class to provide mapping - * of snake-case attributes to camelCase ones - * + * BeanInfo class to provide mapping of snake-case attributes to camelCase ones + * * @author durzod */ public class InputTextBeanInfo extends BsfBeanInfo { + /** * Get the reference decorated class + * + * @return */ @Override public Class> getDecoratedClass() { return InputText.class; } -} \ No newline at end of file +} diff --git a/src/main/java/net/bootsfaces/component/inputText/InputTextRenderer.java b/src/main/java/net/bootsfaces/component/inputText/InputTextRenderer.java index 32685485c..f1b71384d 100644 --- a/src/main/java/net/bootsfaces/component/inputText/InputTextRenderer.java +++ b/src/main/java/net/bootsfaces/component/inputText/InputTextRenderer.java @@ -175,12 +175,9 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce if (visible && label != null) { rw.startElement("label", component); - rw.writeAttribute("for", fieldId, "for"); // "input_" + - // clientId - generateErrorAndRequiredClass(inputText, rw, clientId, inputText.getLabelStyleClass(), responsiveLabelClass, - "control-label"); + rw.writeAttribute("for", fieldId, "for"); // "input_" + clientId + generateErrorAndRequiredClass(inputText, rw, clientId, inputText.getLabelStyleClass(), responsiveLabelClass, "control-label"); writeAttribute(rw, "style", inputText.getLabelStyle()); - rw.writeText(label, null); rw.endElement("label"); } @@ -204,12 +201,13 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce // Input rw.startElement("input", inputText); rw.writeAttribute("id", fieldId, null); // "input_" + clientId + String name = inputText.getName(); - // System.out.println(name); if (null == name) { name = "input_" + clientId; } rw.writeAttribute("name", name, null); + rw.writeAttribute("type", t, null); generateStyleClass(inputText, rw); @@ -234,7 +232,7 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce if ((autocomplete != null) && (autocomplete.equals("off") || autocomplete.equals("false"))) { rw.writeAttribute("autocomplete", "off", null); } - + String v = getValue2Render(context, component); if (inputText instanceof InputSecret) { if (!((InputSecret) inputText).isRenderValue()) { @@ -260,25 +258,23 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce numberOfDivs--; } - // The following lines fix issue #1079 on basic tags (without typeahead). - // They initialize tagsinput manually and empty duplicated 'name' attribute - // on generated input (which holds the original HTML id). if (inputText.isTags() && (!inputText.isTypeahead())) { String id = fieldId; // input id id = id.replace(":", "\\\\:"); // escape the id for jQuery rw.startElement("script", null); - String js = "$('#" + id + "').tagsinput();" + // - "$('#" + id + "').attr('name','');"; + String js = "$('#" + id + "').tagsinput();"; + js += "$('#" + id + "').siblings('.bootstrap-tagsinput').addClass('form-control');"; rw.writeText(js, null); rw.endElement("script"); } Tooltip.activateTooltips(context, inputText); if (inputText.isTypeahead()) { - String id = component.getClientId(); - id = id.replace(":", "_"); // we need to escape the id for jQuery + String componentClientId = component.getClientId(); + // generateStyleClass() add the id as css class before + String escapedClientId = componentClientId.replace(":", "_"); // we need to escape the id for jQuery rw.startElement("script", component); - String typeaheadname = id + "_typeahead"; + String typeaheadname = escapedClientId + "_typeahead"; if (inputText.isTags()) { String js = "var engine = new Bloodhound({" + // "name: '" + typeaheadname + "'," + // @@ -288,7 +284,8 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce "}," + // "queryTokenizer: Bloodhound.tokenizers.whitespace" + // "});"; - js += "$('." + id + "').tagsinput({" + // + + js += "$('." + escapedClientId + "').tagsinput({" + // "typeaheadjs: {" + // " name: 'animals'," + // " displayKey: 'val'," + // @@ -297,16 +294,10 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce "}" + // "});";// - // The following lines fix issue #1079 on tags with typeahead. - // They empty duplicated 'name' attribute on generated input (which holds the original HTML id). - String inputId = fieldId; // input id - inputId = inputId.replace(":", "\\\\:"); // escape the id for jQuery - js += "$('#" + inputId + "').attr('name','');"; + js += "$('." + escapedClientId + "').siblings('.bootstrap-tagsinput').addClass('form-control');"; rw.writeText(js, null); - } else { - String options = ""; options = addOption(options, "hint:" + inputText.isTypeaheadHint()); options = addOption(options, "highlight:" + inputText.isTypeaheadHighlight()); @@ -314,10 +305,8 @@ public void encodeEnd(FacesContext context, UIComponent component) throws IOExce String options2 = ""; options2 = addOption(options2, "limit:" + inputText.getTypeaheadLimit()); options2 = addOption(options2, "name:'" + typeaheadname + "'"); - options2 = addOption(options2, - "source: BsF.substringMatcher(" + getTypeaheadValueArray(inputText) + ")"); - - rw.writeText("$('." + id + "').typeahead({" + options + "},{" + options2 + "});", null); + options2 = addOption(options2, "source: BsF.substringMatcher(" + getTypeaheadValueArray(inputText) + ")"); + rw.writeText("$('." + escapedClientId + "').typeahead({" + options + "},{" + options2 + "});", null); } rw.endElement("script"); }