Decouple navigation and selection with JSF tree-like widget - jsf

I'm looking for a good approach to realize a tree-like JSF widget with the following requirements:
means to expand and collapse tree branches
ajax navigation through clicking on a tree node
multi-selection of nodes / branches via tri-state checkboxes
the former three features must work independent from each other
the solution must be compatible with PrimeFaces
I don't want to fork the framework in terms of writing a custom component
What I've come across:
PrimeFaces p:tree and p:treeTable
built-in selection feature provides a nice implementation with tri-state checkboxes but is tightly coupled to clicking on a node, which makes it unusable in terms of navigation (the selection also changes)
alternatively a custom implementation of the checkbox-column must reinvent the whole tri-state checkbox logic even with pe:triStateCheckbox (PrimeFaces Extensions)
OmniFaces o:tree seems to offer a high level of customization, but also leaves a lot of needle crafting remaining
Any hints, experiences are welcome.

I ended up with a solution build on p:treeTable with selectionMode="checkbox" and p:commandLink for navigation.
To disable the 'full row' mouse click trigger also causing selection changes the JavaScript has been adjusted like this (PrimeFaces 5.3):
<script type="text/javascript">
//<![CDATA[
PrimeFaces.widget.TreeTable.prototype.bindSelectionEvents = function() {
var $this = this,
rowSelector = '> tr.ui-treetable-selectable-node';
this.tbody.off('mouseover.treeTable mouseout.treeTable click.treeTable', rowSelector)
.on('mouseover.treeTable', rowSelector, null, function(e) {
var element = $(this);
if(!element.hasClass('ui-state-highlight')) {
element.addClass('ui-state-hover');
if($this.isCheckboxSelection() && !$this.cfg.nativeElements) {
element.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box').addClass('ui-state-hover');
}
}
})
.on('mouseout.treeTable', rowSelector, null, function(e) {
var element = $(this);
if(!element.hasClass('ui-state-highlight')) {
element.removeClass('ui-state-hover');
if($this.isCheckboxSelection() && !$this.cfg.nativeElements) {
element.find('> td:first-child > div.ui-chkbox > div.ui-chkbox-box').removeClass('ui-state-hover');
}
}
})
.on('click.treeTable', rowSelector, null, function(e) {
//$this.onRowClick(e, $(this));
e.preventDefault();
});
if(this.isCheckboxSelection()) {
var checkboxSelector = this.cfg.nativeElements ? '> tr.ui-treetable-selectable-node > td:first-child :checkbox':
'> tr.ui-treetable-selectable-node > td:first-child div.ui-chkbox-box';
this.tbody.off('click.treeTable-checkbox', checkboxSelector)
.on('click.treeTable-checkbox', checkboxSelector, null, function(e) {
var node = $(this).closest('tr.ui-treetable-selectable-node');
$this.toggleCheckboxNode(node);
});
//initial partial selected visuals
if(this.cfg.nativeElements) {
this.indeterminateNodes(this.tbody.children('tr.ui-treetable-partialselected'));
}
}
};
//]]>
</script>
I also changed some CSS, mainly:
.ui-treetable .ui-treetable-data tr.ui-state-highlight,
.ui-treetable .ui-treetable-data tr.ui-state-hover {
cursor: default;
}

Related

CKEditor 4 : how to apply via API a style to current text

I am fighting with CKEditor in order that after CKEditor is loaded with a content and without selecting any style from toolbar, the changes (new text) made from an user, are automatically set in bold (no toolbar needed for the user).
I tried executing a command on the "click" event setting the bold style but it does not work very well
myEditor.on("instanceReady", function() {
var editable = myEditor.editable();
editable.attachListener( editable, 'click', function() {
myEditor.commands.bold.exec();
});
});
so I changed inserting element with bold style on click event
myEditor.on("instanceReady", function() {
var editable = myEditor.editable();
editable.attachListener( editable, 'click', function() {
var parent = myEditor.getSelection().getStartElement()
//simplified code without check if span already exist
myEditor.insertHtml('<span class="boldStyle">');
myEditor.insertHtml('</span>');
});
});
This works a bit better but I wonder if this approach is a good idea or how I could do better
Thanks

Input multiple with tags without autoCompletion

I have two inputs.
I want the two inputs to have the same look and feel see below:
The first input use autocomplete and allows the user to select a list of terms => I use p:autocomplete (see Primefaces documentation on autocomplete)
This input works fine.
For the second input, I would like to have the same display but without any autocompletion : the user just enter a list of terms with no autocompletion at all.
I tried to have a fake autocomplete that return the value given by the user but it is too slow and the behaviour is not correct when the user quit the input.
Any idea is welcome.
After a quick look at the PrimeFaces javascript code of the autoComplete and a few hours experimenting with it, I came up with a solution. It involves overriding the bindKeyEvents and in it deciding to call the original one or not, adding detection for the space key ('selecting a tag') and when pressed, add the tag and fire the selectionEvent (if ajax is used). Place the following code in your page or in an external javascript file
<script>
//<![CDATA[
if(PrimeFaces.widget.AutoComplete) {
PrimeFaces.widget.AutoComplete = PrimeFaces.widget.AutoComplete.extend ( {
bindKeyEvents: function() {
if (this.input.attr('data-justTags')) {
var $this = this;
this.input.on('keyup.autoComplete', function(e) {
var keyCode = $.ui.keyCode,
key = e.which;
}).on('keydown.autoComplete', function(e) {
var keyCode = $.ui.keyCode;
$this.suppressInput = false;
switch(e.which) {
case keyCode.BACKSPACE:
if ($this.cfg.multiple && !$this.input.val().length) {
$this.removeItem(e, $(this).parent().prev());
e.preventDefault();
}
break;
case keyCode.SPACE:
if($this.cfg.multiple) {
var itemValue = $this.input.val();
var itemDisplayMarkup = '<li data-token-value="' +itemValue + '"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">' + itemValue + '</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>');
if($this.multiItemContainer.children('li.ui-autocomplete-token').length >= $this.cfg.selectLimit) {
$this.input.css('display', 'none').blur();
$this.disableDropdown();
}
$this.invokeItemSelectBehavior(e, itemValue);
}
break;
};
});
} else {
//console.log("Original bindEvents");
this._super();
}
}
});
}
//]]>
</script>
For deciding on when to call the original one or not, I decided to use a passThrough attribute with a data-justTags name. e.g. pt:data-justTags="true" (value does not matter, so pt:data-justTags="false" is identical to pt:data-justTags="true"). A small html snippet of this is:
<p:autoComplete pt:data-justTags="true" multiple="true" value="#{myBean.selectedValues}">
And do not forget to add the xmlns:pt="http://xmlns.jcp.org/jsf/passthrough" namespace declaration.
I found a component that could do the job : http://www.butterfaces.org/tags.jsf

How to disable next/prev buttons animation in a p:wizard?

I have PrimeFaces wizard with some panels, and next/prev buttons is drawn by wizard widget itself... But there is one problem - when i press next button before the last step, it hides with animation... Is it possible to disable this animation and hide next button instantly?
So, you simply want to remove the fading effects on the wizard next button ?
These effects are done with Primefaces Javascript built-in functions, like:
PrimeFaces.widget.Wizard.prototype.showNextNav = function() {
jQuery(this.nextNav).fadeIn();
}
PrimeFaces.widget.Wizard.prototype.hideNextNav = function() {
jQuery(this.nextNav).fadeOut();
}
However, Primefaces creators have let the possibility of overriding them quite easily.
Just add this in your .xhtml page:
<script>
PrimeFaces.widget.Wizard.prototype.hideNextNav = function() {
jQuery(this.nextNav).hide();
}
PrimeFaces.widget.Wizard.prototype.showNextNav = function() {
jQuery(this.nextNav).show();
}
</script>
Tested and working on PF 5.1.

PJax not working with MVC project

I've followed the samples. I added a _PjaxLayout:
<title>#ViewBag.Title</title>
#RenderBody()
Modified my _Layout:
<div id="shell">
#RenderBody()
</div>
<script type="text/javascript">
$(function () {
// pjax
$.pjax.defaults.timeout = 5000;
$('a').pjax('#shell');
})
</script>
Updated ViewStart:
#{
if (Request.Headers["X-PJAX"] != null) {
Layout = "~/Views/Shared/_PjaxLayout.cshtml";
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
Yet every time I click on an 'a' tag, the pjax code doesn't get called. It's as if the selector isn't working when I set up pjax. What am I doing wrong?
UPDATE:
If I do this:
$('document').ready(function () {
$('a').pjax({
container: '#shell',
timeout: 5000
});
});
I see the pjax code getting hit and the Request headers get updated, and the new content loads on the page, but the styling and layout get really messed up and duplicated...
UPDATE:
Inspecting the DOM after this craziness happens reveals that the new page content is getting loaded directly into the anchor that I click, instead of into the element with id #shell. WTF?
You are using a legacy syntax, the new pjax uses the following:
$(document).pjax('a', '#shell', { fragment: '#shell' });
Also I am not familiar with the language you use, but in order to make pjax happen there has to be an HTML element with the id shell in your ViewStart.
As I am not sure about the syntax in that language, try something similar to this for testing:
#{
if (Request.Headers["X-PJAX"] != null) {
echo "<ul id="shell"> pjaaxxx </ul>"; // Would work in php, update syntax
} else {
Layout = "~/Views/Shared/_Layout.cshtml";
}
}
I am not seeing that syntax as valid in the PJax documentation.
Are you sure you didn't mean $(document).pjax('a',{});?
$.pjax immediately executes from what I can tell.

Kendo UI - Placeholder - Style

I have a Kendo UI datepicker with placeholder data. Here is the HTML:
<input type="text" class="datepicker"' placeholder="yyyy-mm-dd" />
Here is the JavaScript:
var start = $(".datepicker").kendoDatePicker({
format: "yyyy-MM-dd",
parseFormats: ["MM/dd/yyyy"],
change: startChange
}).data("kendoDatePicker");
The Kendo UI datepicker displays the placeholder data in the same style as user entered data. I would like to style the placeholder data differently. Specifically, I would like the text to be gray and italicized. When user enters data, the style changes to solid black (non-italicized). Any thoughts on how to do this?
Well, placeholder is an HTML5 attibute and isn't specic to Kendo controls. As I understand it Kendo doesn't offer any support for placeholder over what is supported by the browser, and remember that only some browsers support this attribute; IE does not.
Anyway, to style the placeholder you'll have to use vendor prefix CSS properties, see here.
I use this..it will work on your HTML and you can style it too :)
<script>
// This adds 'placeholder' to the items listed in the jQuery .support object.
jQuery(function() {
jQuery.support.placeholder = false;
test = document.createElement('input');
if('placeholder' in test) jQuery.support.placeholder = true;
});
// This adds placeholder support to browsers that wouldn't otherwise support it.
$(function() {
if(!$.support.placeholder) {
var active = document.activeElement;
$(':text').focus(function () {
if ($(this).attr('placeholder') != '' && $(this).val() == $(this).attr('placeholder')) {
$(this).val('').removeClass('hasPlaceholder');
}
}).blur(function () {
if ($(this).attr('placeholder') != '' && ($(this).val() == '' || $(this).val() == $(this).attr('placeholder'))) {
$(this).val($(this).attr('placeholder')).addClass('hasPlaceholder');
}
});
$(':text').blur();
$(active).focus();
$('form:eq(0)').submit(function () {
$(':text.hasPlaceholder').val('');
});
}
});
</script>

Resources