Group by three common elements (XML to XML) - xslt-2.0

We have a requirement in which we need to group by segments which are sharing three things common...I have attached the sample input and desire output..It would be great if someone help.
We need to make a group on the basis of Country, company name and Month of birth.
I have tried and I am beginner in this...so couldn't succeeded.
This is our input
<?xml version='1.0' encoding='utf-8'?>
<EMPDTLS>
<EMP>
<FIRST_NAME>John</FIRST_NAME>
<LAST_NAME>Mathew</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>DEC</MONTH_OF_BIRTH>
<COMPANY_NAME>TCS</COMPANY_NAME>
<BAND>B</BAND>
</EMP>
<EMP>
<FIRST_NAME>Luis</FIRST_NAME>
<LAST_NAME>Phillip</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>DEC</MONTH_OF_BIRTH>
<COMPANY_NAME>TCS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>Nick</FIRST_NAME>
<LAST_NAME>Tatar</LAST_NAME>
<COUNTRY>USA</COUNTRY>
<MONTH_OF_BIRTH>JAN</MONTH_OF_BIRTH>
<COMPANY_NAME>CTS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>Zuza</FIRST_NAME>
<LAST_NAME>Bark</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>JUNE</MONTH_OF_BIRTH>
<COMPANY_NAME>TCS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>Jane</FIRST_NAME>
<LAST_NAME>ellis</LAST_NAME>
<COUNTRY>ENGLAND</COUNTRY>
<MONTH_OF_BIRTH>JUNE</MONTH_OF_BIRTH>
<COMPANY_NAME>IBM</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>SANJAY</FIRST_NAME>
<LAST_NAME>BAWARI</LAST_NAME>
<COUNTRY>ENGLAND</COUNTRY>
<MONTH_OF_BIRTH>JUNE</MONTH_OF_BIRTH>
<COMPANY_NAME>IBM</COMPANY_NAME>
<BAND>B</BAND>
</EMP>
<EMP>
<FIRST_NAME>Akhi</FIRST_NAME>
<LAST_NAME>Mahe</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>SEPT</MONTH_OF_BIRTH>
<COMPANY_NAME>IBM</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>Vishh</FIRST_NAME>
<LAST_NAME>Bombard</LAST_NAME>
<COUNTRY>GERMANY</COUNTRY>
<MONTH_OF_BIRTH>OCT</MONTH_OF_BIRTH>
<COMPANY_NAME>IBM</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>Sharon</FIRST_NAME>
<LAST_NAME>Watson</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>JULY</MONTH_OF_BIRTH>
<COMPANY_NAME>CTS</COMPANY_NAME>
<BAND>B</BAND>
</EMP>
<EMP>
<FIRST_NAME>Poo</FIRST_NAME>
<LAST_NAME>Smith</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>SEPT</MONTH_OF_BIRTH>
<COMPANY_NAME>CTS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>John</FIRST_NAME>
<LAST_NAME>Smith</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>DEC</MONTH_OF_BIRTH>
<COMPANY_NAME>TCS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
</EMPDTLS>
<Desired Output>
<?xml version='1.0' encoding='utf-8'?>
<EMPDTLS>
<EmpGrp>
<EMP>
<FIRST_NAME>John</FIRST_NAME>
<LAST_NAME>Mathew</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>DEC</MONTH_OF_BIRTH>
<COMPANY_NAME>TCS</COMPANY_NAME>
<BAND>B</BAND>
</EMP>
<EMP>
<FIRST_NAME>Luis</FIRST_NAME>
<LAST_NAME>Phillip</LAST_NAME>
<COUNTRY>INDIA</COUNTRY>
<MONTH_OF_BIRTH>DEC</MONTH_OF_BIRTH>
<COMPANY_NAME>TCS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
</EmpGrp>
<EmpGrp>
<EMP>
<FIRST_NAME>Nick</FIRST_NAME>
<LAST_NAME>Tatar</LAST_NAME>
<COUNTRY>USA</COUNTRY>
<MONTH_OF_BIRTH>JAN</MONTH_OF_BIRTH>
<COMPANY_NAME>CTS</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
</EmpGrp>
<EmpGrp>
<EMP>
<FIRST_NAME>Jane</FIRST_NAME>
<LAST_NAME>ellis</LAST_NAME>
<COUNTRY>ENGLAND</COUNTRY>
<MONTH_OF_BIRTH>JUNE</MONTH_OF_BIRTH>
<COMPANY_NAME>IBM</COMPANY_NAME>
<BAND>A</BAND>
</EMP>
<EMP>
<FIRST_NAME>SANJAY</FIRST_NAME>
<LAST_NAME>BAWARI</LAST_NAME>
<COUNTRY>ENGLAND</COUNTRY>
<MONTH_OF_BIRTH>JUNE</MONTH_OF_BIRTH>
<COMPANY_NAME>IBM</COMPANY_NAME>
<BAND>B</BAND>
</EMP>
</EmpGrp>
**

Composite grouping keys are a bit easier in XSLT 3 (the latest version of XSLT since the summer of 2017 and supported by Saxon 9.8 or 9.9 as well as Altova 2017 or 2018 or 2019) as there you can use e.g. for-each-group composite="yes" group-by="COUNTRY, COMPANY_NAME, MONTH_OF_BIRTH":
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output indent="yes"/>
<xsl:template match="EMPDTLS">
<xsl:copy>
<xsl:for-each-group select="EMP" composite="yes" group-by="COUNTRY, COMPANY_NAME, MONTH_OF_BIRTH">
<EmpGrp>
<xsl:copy-of select="current-group()"/>
</EmpGrp>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
You can test it online at https://xsltfiddle.liberty-development.net/jyRYYhU/1.
As for XSLT 2, see https://cranesoftwrights.github.io/books/ptux/index.htm for a thorough treatment of XSLT if you have no other text book available or also see the spec https://www.w3.org/TR/xslt20/#grouping-examples which has "A Composite Grouping Key" as the second example by nesting for-each-group. Another technique in XSLT 2 is to concatenate the various items composing the grouping key to a string e.g. group-by="string-join((COUNTRY, COMPANY_NAME, MONTH_OF_BIRTH), '|')", making sure the separator character (e.g. |) is not contained in any key item value.

Related

Theme Resources to define gradient stop color UWP

I am creating UWP application.I have few LinearGradientBrushes, where the color is set directly in the LinearGradientBrush reference as GradientStops. However, I want to have a predefined set of colors defined in the resource distionary that I can use a a reference for each GradientStop, so that changing the color scheme for the application is a matter of changing the values of the SolidColorBrushes:
<!--Resource Dictionary -->
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="stop1" Color="#FF5A5A5A"/>
<SolidColorBrush x:Key="stop2" Color="#FF222222"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="stop1" Color="Black"/>
<SolidColorBrush x:Key="stop2" Color="White"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="stop1" Color="Black"/>
<SolidColorBrush x:Key="stop2" Color="White"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<!-- control Template-->
<LinearGradientBrush x:Key="gradient">
<GradientStop Color="{Binding Source={Themeresource stop1},Path=Color}" Offset="0"/>
<GradientStop Color="{Binding Source={Themeresource stop2},Path=Color}" Offset="1"/>
</LinearGradientBrush>
Its Giving error that nam/key stop1 is not Found
The problem is stop1 is static resource but not Themeresource . So, we need edit binding source as StaticResource.
<LinearGradientBrush x:Key="gradient">
<GradientStop Color="{Binding Source={StaticResource stop1},Path=Color}" Offset="0"/>
<GradientStop Color="{Binding Source={StaticResource stop2},Path=Color}" Offset="1"/>
</LinearGradientBrush>
Update
For the testing, if we place above in ResourceDictionary, it will work.
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="stop1" Color="#FF5A5A5A"/>
<SolidColorBrush x:Key="stop2" Color="#FF222222"/>
</ResourceDictionary>
<ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="stop1" Color="Black"/>
<SolidColorBrush x:Key="stop2" Color="White"/>
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="stop1" Color="Black"/>
<SolidColorBrush x:Key="stop2" Color="White"/>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<!-- control Template-->
<LinearGradientBrush x:Key="gradient">
<GradientStop Color="{Binding Source={ThemeResource stop1},Path=Color}" Offset="0"/>
<GradientStop Color="{Binding Source={ThemeResource stop2},Path=Color}" Offset="1"/>
</LinearGradientBrush>
</ResourceDictionary>
</Page.Resources>
The above problem can be solved by using binding
public LinearGradientBrush GradientBrush
{
get { return _GradientBrush; }
set
{
_GradientBrush = value;
RaisePropertyChanged("GradientBrush");
}
}
GradientBrush = GetGradientBrush();
public static LinearGradientBrush GetGradientBrush()
{
var grColor1 = ((SolidColorBrush)Application.Current.Resources["stop1"]).Color;
var grColor2 = ((SolidColorBrush)Application.Current.Resources["stop2"]).Color;
LinearGradientBrush lgBrush = new LinearGradientBrush();
lgBrush.GradientStops.Add(new GradientStop() { Color = grColor1, Offset = 0.1 });
lgBrush.GradientStops.Add(new GradientStop() { Color = grColor2, Offset = 0.9 });
lgBrush.StartPoint = new Point(0, 1);
lgBrush.EndPoint = new Point(1, 0);
return lgBrush;
}
<Grid Background="{Binding GradientBrush}" >

listview item space xamarin android

I want to add a space and shade between each element in listview.
How the tool is drawn xml?
Create a xml file Shadow.xml in Android drawable folder.
<?xml version="1.0" encoding="utf-8" ?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item >
<shape
android:shape="rectangle">
<solid android:color="#android:color/darker_gray" />
<corners android:radius="5dp"/>
</shape>
</item>
<item android:right="6dp" android:left="6dp" android:bottom="9dp">
<shape
android:shape="rectangle">
<solid android:color="#android:color/white"/>
<corners android:radius="5dp"/>
</shape>
</item>
</layer-list>
Uasge: Set the shadow with background of Layout. Use divider property to set the space between each element in listview.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/parent"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:gravity="center"
android:background="#drawable/shadow"
android:orientation="vertical">
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="20px"
android:divider="#android:color/darker_gray"
android:layerType="software"
/>
</LinearLayout>
MainActivity:
ListView listView = FindViewById<ListView>(Resource.Id.listview);
string[] s = new string[] { "a", "b", "c","d","e","f","g","h","i","j","k" };
ArrayAdapter<string> arrayAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, s);
listView.Adapter = arrayAdapter;

Add settings to the Basic Settings dialog for a custom control

Hopefully not too much of an Orbeon-noob question. I have built a custom control for Orbeon (a simple slider for now) and was wanting to add the ability to change the min, max and step parameters for the range input in the Basic Settings dialog. I have had a look at the Dynamic Driven Dropdown and have added the control-details section in the control metadata, but I am stumped on how to get them to show up and how to use the value on the actual input element. Any help / example code would be hugely appreciated.
<xbl:xbl xmlns:xh="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:saxon="http://saxon.sf.net/"
xmlns:oxf="http://www.orbeon.com/oxf/processors"
xmlns:xbl="http://www.w3.org/ns/xbl"
xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xbl:binding id="fr-slider" element="fr|slider"
xxf:external-events="fr-value-changed"
xxbl:mode="lhha binding value">
<metadata xmlns="http://orbeon.org/oxf/xml/form-builder">
<display-name lang="en">Slider</display-name>
<icon lang="en">
<small-icon>/forms/orbeon/builder/images/timeline_marker.png</small-icon>
<large-icon>/forms/orbeon/builder/images/timeline_marker.png</large-icon>
</icon>
<datatype>xf:number</datatype>
<template>
<fr:slider>
<xf:label ref=""/>
<xf:hint ref=""/>
<xf:help ref=""/>
<xf:alert ref=""/>
<xf:min ref=""/>
<xf:max ref=""/>
<xf:step ref=""/>
</fr:slider>
</template>
<control-details>
<xf:input ref="xf:min/#ref" type="number">
<xf:label>Minimum Value</xf:label>
<xf:hint />
</xf:input>
<xf:input ref="xf:max/#ref" type="number">
<xf:label>Maximum Value</xf:label>
<xf:hint />
</xf:input>
<xf:input ref="xf:step/#ref" type="number">
<xf:label>Step Size</xf:label>
<xf:hint>Smallest change in value the slider will allow</xf:hint>
</xf:input>
</control-details>
</metadata>
<xbl:resource>
<xbl:style>
input.fr-slider { width: 100% };
</xbl:style>
</xbl:resource>
<xbl:template xxbl:transform="oxf:unsafe-xslt">
<xsl:transform version="2.0">
<xsl:import href="oxf:/oxf/xslt/utils/xbl.xsl"/>
<xsl:template match="/*">
<xh:input type="range" min="0" max="10" step="1" class="fr-slider"/>
</xsl:template>
</xsl:transform>
</xbl:template>
</xbl:binding>
</xbl:xbl>
To get the inputs in the <control-detail> to show in the Basic Settings dialog, you need to add a lang parameter to the <xf:label> and <xf:hint> elements (thanks to #avernet for solving this).
Below is a full example of a custom control cust:betterinput that uses an xhtml input element for its input. It uses custom settings (and also the data type [set in Control Settings -> Validation and Alerts -> Data Type]) to configure parameters on the html element (note that the custom parameters have been changed to control parameters). Javascript is used to sync the value between the xhtml input and the xforms input (so that the value is captured by Orbeon). The example is based on number control included in Orbeon
xbl/cust/betterinput/betterinput.xbl
<xbl:xbl xmlns:xh="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:saxon="http://saxon.sf.net/"
xmlns:exf="http://www.exforms.org/exf/1-0"
xmlns:oxf="http://www.orbeon.com/oxf/processors"
xmlns:xbl="http://www.w3.org/ns/xbl"
xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cust="http://www.cust.com/">
<xbl:script src="/xbl/cust/betterinput/betterinput.js"/>
<xbl:binding
id="cust-betterinput"
element="cust|betterinput"
xxbl:mode="lhha binding value focus"
xxbl:label-for="html-input">
<metadata xmlns="http://orbeon.org/oxf/xml/form-builder">
<display-name lang="en">Better Input</display-name>
<icon lang="en">
<small-icon>/forms/orbeon/builder/images/input.png</small-icon>
<large-icon>/forms/orbeon/builder/images/input.png</large-icon>
</icon>
<description lang="en"/>
<templates>
<view>
<cust:betterinput type="" prefix="" suffix="">
<xf:label ref=""/>
<xf:hint ref=""/>
<xf:help ref=""/>
<xf:alert ref=""/>
</cust:betterinput>
</view>
</templates>
<control-details>
<xf:input ref="#type">
<xf:label lang="en">Input Type</xf:label>
<xf:hint lang="en">HTML5 Input Type</xf:hint>
</xf:input>
<xf:input ref="#prefix">
<xf:label lang="en">Input Prefix</xf:label>
<xf:hint/>
</xf:input>
<xf:input ref="#suffix">
<xf:label lang="en">Input Suffix</xf:label>
<xf:hint/>
</xf:input>
</control-details>
</metadata>
<xbl:resources>
<xbl:style src="/xbl/cust/betterinput/betterinput.css"/>
</xbl:resources>
<xbl:template xxbl:transform="oxf:unsafe-xslt">
<xsl:transform version="2.0">
<xsl:import href="oxf:/oxf/xslt/utils/xbl.xsl"/>
<xsl:template match="/*">
<xsl:variable
name="js-object"
as="xs:string"
select="'YAHOO.xbl.cust.BetterInput.instance(this)'"/>
<xf:group>
<xf:action type="javascript" ev:event="xforms-disabled" ev:target="#observer">
<xsl:value-of select="$js-object"/>.destroy();
</xf:action>
<xf:var name="binding" value="xxf:binding('cust-betterinput')"/>
<xf:var name="view"
value="exf:readonly($binding) and property('xxf:readonly-appearance') = 'static'"/>
<xf:action
ev:target="#observer"
ev:event="xforms-enabled xforms-value-changed">
<xxf:script>
<xsl:value-of select="$js-object"/>.updateWithServerValue();
</xxf:script>
</xf:action>
<xf:action
ev:target="#observer"
ev:event="DOMFocusOut">
<xxf:script>
<xsl:value-of select="$js-object"/>.updateWithServerValue();
</xxf:script>
</xf:action>
<xf:var name="htmlinputs" value="' email url color number datetime-local '" />
<xsl:copy-of select="xxbl:parameter(., 'type')"/>
<xsl:copy-of select="xxbl:parameter(., 'prefix')"/>
<xsl:copy-of select="xxbl:parameter(., 'suffix')"/>
<xf:group ref="$binding[not($view)]">
<xf:input ref="." class="betterinput-xform-input xforms-hidden">
<xf:action type="javascript" id="xf-ro" ev:event="xforms-readonly"><xsl:value-of select="$js-object"/>.readonly();</xf:action>
<xf:action type="javascript" id="xf-rw" ev:event="xforms-readwrite"><xsl:value-of select="$js-object"/>.readwrite();</xf:action>
</xf:input>
<xh:span class="{{(if ($prefix) then 'input-prepend' else (), if ($suffix) then 'input-append' else ())}}">
<xf:group class="add-on" ref=".[$prefix]"><xf:output value="$prefix"/></xf:group>
<xh:input id="html-input" class="betterinput-html-input" type="{{
if (not(type = '') and contains($htmlinputs, concat(' ', $type, ' '))) then
$type
else
if (contains(' decimal integer double ', concat(' ', xxf:type($binding), ' '))) then
'number'
else
if (contains($htmlinputs, concat(' ', xxf:type($binding), ' '))) then
xxf:type($binding)
else
'text'
}}"/>
<xf:group class="add-on" ref=".[$suffix]"><xf:output value="$suffix"/></xf:group>
</xh:span>
</xf:group>
<!-- Static readonly mode -->
<xf:group ref="$binding[$view]" class="{{(if ($prefix) then 'input-prepend' else (), if ($suffix) then 'input-append' else ())}}">
<xf:group class="add-on" ref=".[$prefix]"><xf:output value="$prefix"/></xf:group>
<xf:input ref="$binding[$view]" class="betterinput-html-input" />
<xf:group class="add-on" ref=".[$suffix]"><xf:output value="$suffix"/></xf:group>
</xf:group>
</xf:group>
</xsl:template>
</xsl:transform>
</xbl:template>
</xbl:binding>
</xbl:xbl>
xbl/cust/betterinput/betterinput.js
(function() {
var $ = ORBEON.jQuery;
var AS = ORBEON.xforms.server.AjaxServer;
var Document = ORBEON.xforms.Document;
YAHOO.namespace("xbl.cust");
YAHOO.xbl.cust.BetterInput = function() {};
ORBEON.xforms.XBL.declareClass(YAHOO.xbl.cust.BetterInput, "xbl-cust-betterinput");
YAHOO.xbl.cust.BetterInput.prototype = {
xformsInputElement: null,
visibleInputElement: null,
prefixElement: null,
prefix: null,
init: function() {
// Get information from the DOM
console.log('betterinput init');
this.xformsInputElement = YAHOO.util.Dom.getElementsByClassName("betterinput-xform-input", null, this.container)[0];
this.visibleInputElement = YAHOO.util.Dom.getElementsByClassName("betterinput-html-input", null, this.container)[0];
// Properties
// Find prefix based on class/control name, as this JS can be used with fr:number and fr:currency and properties use the control name
var controlClassPrefix = null;
var containerClasses = this.container.className.split(" ");
for (var classIndex = 0; classIndex < containerClasses.length; classIndex++) {
var currentClass = containerClasses[classIndex];
if (currentClass.indexOf("xbl-cust-") == 0) {
controlClassPrefix = currentClass;
break;
}
}
this.prefixElement = YAHOO.util.Dom.getElementsByClassName(controlClassPrefix + "-prefix", null, this.container)[0];
this.prefix = Document.getValue(this.prefixElement.id);
// Register listeners
// Restore input type, send the value to the server, and updates value after server response
$(this.visibleInputElement).on('change blur', _.bind(function(e) {
this.sendValueToServer();
var formId = $(this.container).parents('form').attr('id');
// Always update visible value with XForms value
// - relying just value change event from server is not enough
// - value change not dispatched if server value hasn't changed
// - if visible changed, but XForms hasn't, we still need to show XForms value
// - see: https://github.com/orbeon/orbeon-forms/issues/1026
AS.nextAjaxResponse(formId).then(_.bind(this.updateWithServerValue, this));
}, this));
$(this.visibleInputElement).on('keypress', _.bind(function(e) {
if (e.which == 13)
this.sendValueToServer();
}, this));
},
setFocus: function() {
this.visibleInputElement.focus();
},
sendValueToServer: function() {
var newValue = this.visibleInputElement.value;
Document.setValue(this.xformsInputElement.id, newValue);
},
updateWithServerValue: function() {
var value = Document.getValue(this.xformsInputElement.id);
this.visibleInputElement.value = value;
// Also update disabled because this might be called upon an iteration being moved, in which case all the control properties must be updated
this.visibleInputElement.disabled = YAHOO.util.Dom.hasClass(this.xformsInputElement, "xforms-readonly");
},
readonly: function() {
this.visibleInputElement.disabled = true;
},
readwrite: function() {
this.visibleInputElement.disabled = false;
},
};
})();

How do I add design-time properties to this XBL control?

Using Orbeon, I have the following XBL for a simple control:
<xbl:xbl xmlns:xh="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:xxi="http://orbeon.org/oxf/xml/xinclude"
xmlns:xxf="http://orbeon.org/oxf/xml/xforms"
xmlns:fr="http://orbeon.org/oxf/xml/form-runner"
xmlns:saxon="http://saxon.sf.net/"
xmlns:xbl="http://www.w3.org/ns/xbl"
xmlns:xxbl="http://orbeon.org/oxf/xml/xbl"
xmlns:nrs="http://nrs.foo/2014/xml/xbl">
<xbl:script src="/xbl/nrs/foo/foo.js"/>
<xbl:binding id="nrs-foo" element="nrs|foo" xxbl:mode="lhha binding value">
<metadata xmlns="http://orbeon.org/oxf/xml/form-builder">
<display-name lang="en">Foo</display-name>
<templates>
<view>
<nrs:foo>
<xf:label ref=""/>
<xf:hint ref=""/>
<xf:help ref=""/>
<xf:alert ref=""/>
</nrs:foo>
</view>
</templates>
</metadata>
<xbl:template>
<xf:group xxbl:scope="outer">
<xf:group xbl:attr="model context ref bind">
<!-- Constructor -->
<xf:group xxbl:scope="inner">
<xxf:script id="xf-en" ev:event="xforms-enabled">YAHOO.xbl.nrs.foo.instance(this).init();</xxf:script>
</xf:group>
</xf:group>
<xf:input class="nrs-foo-json" ref="xxf:binding('nrs-foo')" xxbl:scope="inner" />
</xf:group>
</xbl:template>
</xbl:binding>
.. and accompanying JS module:
(function() {
var $ = ORBEON.jQuery;
var Document = ORBEON.xforms.Document;
YAHOO.namespace("xbl.nrs");
YAHOO.xbl.nrs.Foo= function() {};
ORBEON.xforms.XBL.declareClass(YAHOO.xbl.nrs.Foo, "xbl-nrs-foo");
YAHOO.xbl.nrs.Foo.prototype = {
fooInput : null,
init: function() {
var self = this;
self.fooInput = $(this.container).find( '.nrs-foo-json' );
// get design time property
},
};
})();
How would I modify the XBL to get a design-time property (say a string called 'URL', that I can configure on the properties panel in the form designer), that is stored in the form definition and I can access in the JS code (at place marked by comment)?
Check how it is done in autocomplete.xbl, and more specifically at the the content of <control-details> inside <metadata>. In that case the value set in Form Builder through the Control Settings dialog ends up in the resource="..." attribute on the control, and accessed in the XBL through the resource-avt variable.
(Note that there are some complications there as we want the value to be interpreted as an AVT, and the variable to be accessible both in the inner and outer scope, but hopefully this example helps you get the idea.)

JavaFX can't show contextmenu in FXML Application

i'm beginning with JavaFX.
I'm testing to create a FXML project and trying to display a context menu when i click into a row of the tableview, but i canĀ“t see my context menu.
My code is:
package fxmltableview;
import java.net.URL;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
/**
*
* #author aCedano
*/
public class FXMLTableViewController implements Initializable {
#FXML private TableView<Person> tableView;
#FXML private TableColumn<Person, String> firstNameColumn;
#FXML private TableColumn<Person, String> lastNameColumn;
#FXML private TableColumn<Person, String> testColumn;
#FXML private ContextMenu resultadoContextMenu;
Connection con;
private DBClass objDbClass;
private ObservableList<Person> data;
#Override
public void initialize(URL location, ResourceBundle resources) {
assert tableView != null : "fx:id=\"tableView\" was not injected: check your FXML file...";
firstNameColumn.setCellValueFactory(new PropertyValueFactory<>("test"));
lastNameColumn.setCellValueFactory(new PropertyValueFactory<>("firstName"));
testColumn.setCellValueFactory(new PropertyValueFactory<>("lastName"));
objDbClass = new DBClass();
try{
con = objDbClass.getConnection();
buildData();
tableView.setRowFactory(
(TableView<Person> tableView1) -> {
final TableRow<Person> row = new TableRow<>();
final ContextMenu rowMenu = new ContextMenu();
MenuItem editItem = new MenuItem("Edit");
MenuItem removeItem = new MenuItem("Delete");
removeItem.setOnAction((ActionEvent event) -> {
tableView1.getItems().remove(row.getItem());
});
rowMenu.getItems().addAll(editItem, removeItem);
row.contextMenuProperty().bind(
Bindings.when(Bindings.isNotNull(row.itemProperty()))
.then(rowMenu)
.otherwise((ContextMenu)null));
return row;
});
tableView.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent e) -> {
if (e.getButton() == MouseButton.SECONDARY)
resultadoContextMenu.show(tableView, e.getScreenX(), e.getScreenY());
});
}
catch(ClassNotFoundException | SQLException ce){
}
}
//Populate table
public void buildData(){
data = FXCollections.observableArrayList();
try{
String SQL = "Select * from tbltest Order By test";
ResultSet rs = con.createStatement().executeQuery(SQL);
while(rs.next()){
Person cm = new Person();
cm.setFirstName(rs.getString("test"));
cm.setLastName(rs.getString("nombre"));
cm.setTest(rs.getString("apellido"));
data.add(cm);
}
tableView.setItems(data);
tableView.getItems();
}
catch(SQLException e){
System.out.println("Error on Building Data");
}
}
}
I'm using Scene builder and my FXML file is:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.effect.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.paint.*?>
<?import javafx.geometry.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.cell.*?>
<?import javafx.collections.*?>
<?import fxmltableview.*?>
<!--/*<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxmltableview.FXMLDocumentController">
<children>
<Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
<Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" />
</children>
</AnchorPane>*/-->
<GridPane alignment="CENTER" hgap="10.0" prefHeight="689.0" prefWidth="710.0" vgap="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fxmltableview.FXMLTableViewController">
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<children>
<Button mnemonicParsing="false" text="Button" GridPane.rowIndex="1">
<effect>
<DropShadow />
</effect>
</Button>
<Label style="-fx-font: NORMAL 20 Tahoma;" text="Address Book" textOverrun="CENTER_ELLIPSIS" GridPane.rowIndex="2">
<font>
<Font name="Gill Sans MT Bold" size="13.0" />
</font>
<textFill>
<LinearGradient endX="1.0" endY="1.0" startX="0.5769230769230769">
<stops>
<Stop color="BLACK" />
<Stop color="WHITE" offset="1.0" />
</stops>
</LinearGradient>
</textFill></Label>
<TableView fx:id="tableView" prefHeight="265.0" prefWidth="502.0" tableMenuButtonVisible="true" GridPane.columnIndex="0" GridPane.rowIndex="3">
<columns>
<TableColumn fx:id="firstNameColumn" prefWidth="100" text="First Name">
<cellValueFactory>
<PropertyValueFactory property="firstName" />
</cellValueFactory>
<contextMenu>
<ContextMenu fx:id="resultadoContextMenu">
<items>
<MenuItem mnemonicParsing="false" text="Unspecified Action" />
</items>
</ContextMenu>
</contextMenu>
</TableColumn>
<TableColumn fx:id="lastNameColumn" prefWidth="100" text="Last Name">
<cellValueFactory>
<PropertyValueFactory property="lastName" />
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="testColumn" prefWidth="300" text="Email Address">
<cellValueFactory>
<PropertyValueFactory property="test" />
</cellValueFactory>
</TableColumn>
</columns>
<items>
<FXCollections fx:factory="observableArrayList">
<!--/* <Person email="jacob.smith#example.com" firstName="Jacob" lastName="Smith" />
<Person email="isabella.johnson#example.com" firstName="Isabella" lastName="Johnson" />
<Person email="ethan.williams#example.com" firstName="Ethan" lastName="Williams" />
<Person email="emma.jones#example.com" firstName="Emma" lastName="Jones" />
<Person email="michael.brown#example.com" firstName="Michael" lastName="Brown" />/*-->
</FXCollections>
</items>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</children>
<columnConstraints>
<ColumnConstraints />
</columnConstraints>
<rowConstraints>
<RowConstraints />
<RowConstraints />
<RowConstraints />
<RowConstraints />
</rowConstraints>
</GridPane>
You have null condition to show your context menu. Add data to your tableView and click on row. (I think your ResultSet is empty)
tableView.setItems(data);

Resources