diff --git a/brjs-sdk/sdk/libs/javascript/br-presenter/src/br/presenter/control/selectionfield/JQueryAutoCompleteControl.js b/brjs-sdk/sdk/libs/javascript/br-presenter/src/br/presenter/control/selectionfield/JQueryAutoCompleteControl.js
index b22c3853b..2674aae9b 100644
--- a/brjs-sdk/sdk/libs/javascript/br-presenter/src/br/presenter/control/selectionfield/JQueryAutoCompleteControl.js
+++ b/brjs-sdk/sdk/libs/javascript/br-presenter/src/br/presenter/control/selectionfield/JQueryAutoCompleteControl.js
@@ -47,6 +47,7 @@ function JQueryAutoCompleteControl() {
/** @private */
this.m_eElement = {};
+ this.m_jQueryInput = null;
this.m_bOpenOnFocus = false;
this.m_sAppendTo = 'body';
this._viewOpened = false;
@@ -77,31 +78,31 @@ JQueryAutoCompleteControl.prototype.setPresentationNode = function(oPresentation
throw new InvalidControlModelError('JQueryAutoCompleteControl', 'AutoCompleteSelectionField');
}
- this.m_eElement.value = oPresentationNode.value.getValue();
+ this.m_eElement.value = oPresentationNode.value.getFormattedValue();
this._valueChangedListener = oPresentationNode.value.addUpdateListener(this, '_valueChanged');
this.m_oPresentationNode = oPresentationNode;
};
JQueryAutoCompleteControl.prototype.onViewReady = function() {
- var oJqueryInput = jQuery(this.m_eElement);
+ this.m_jQueryInput = jQuery(this.m_eElement);
var self = this;
- this._viewOpened = true;
-
- oJqueryInput.keydown(function(event, oUi) {
- if (event.which == 13) // Enter.
- {
- self._setValue(self.m_oPresentationNode, this, oUi);
- event.stopImmediatePropagation();
- event.preventDefault();
- this.blur();
- return false;
- }
- });
- oJqueryInput.autocomplete({
+ this.m_jQueryInput.autocomplete({
+ delay: this.delay || 0,
minLength: self.m_nMinCharAmount || 0,
autoFocus: true,
appendTo: self.m_sAppendTo,
+ open: function() {
+ // ensure menu is on top of elements
+ self.m_jQueryInput.autocomplete('widget').css('z-index', 999999);
+
+ self.m_jQueryInput.addClass('autocomplete-menu-open');
+
+ return false;
+ },
+ close: function() {
+ self.m_jQueryInput.removeClass('autocomplete-menu-open');
+ },
source: function(request, response) {
var sTerm = request.term;
self.m_oPresentationNode.getAutoCompleteList(sTerm, function(pValues) {
@@ -110,9 +111,6 @@ JQueryAutoCompleteControl.prototype.onViewReady = function() {
},
select: function(event, oUi) {
self._setValue(self.m_oPresentationNode, this, oUi);
- // don't propagate this to the keydown (if it's triggered by an enter)
- event.stopImmediatePropagation();
- event.preventDefault();
// if the selection is triggered by a click, not by pressing enter, then blur
if (self.m_bBlurAfterClick === true) {
var ie8LeftClick = !event.button && !event.which;
@@ -126,55 +124,91 @@ JQueryAutoCompleteControl.prototype.onViewReady = function() {
}
});
+ this._onDocumentFocus = this._onDocumentFocus.bind(this);
+ this.m_jQueryInput.on('focus', this._onDocumentFocus);
+
+ this._onScroll = this._onScroll.bind(this);
+ jQuery( document.body ).on('mousewheel wheel', this._onScroll);
+
+ this._viewOpened = true;
+};
+
+JQueryAutoCompleteControl.prototype._onScroll = function(wheelEvent) {
+ var isEventTargetChildOfAutoComplete = this.m_jQueryInput.autocomplete('widget')[0].contains(wheelEvent.target);
+
+ if( isEventTargetChildOfAutoComplete === false ) {
+ this.m_jQueryInput.autocomplete('close');
+ }
+};
+
+JQueryAutoCompleteControl.prototype._onDocumentFocus = function() {
+ this.m_jQueryInput.select();
+
if (this.m_bOpenOnFocus) {
- oJqueryInput.focus(function(e) {
- jQuery(this).autocomplete('search', oJqueryInput.val() || '');
- });
+ this.m_jQueryInput.autocomplete('search', this.m_jQueryInput.val() || '');
}
};
JQueryAutoCompleteControl.prototype._setValue = function(oPresentationNode, oInput, oUi) {
- if (oPresentationNode.isValidOption(oInput.value)) {
- oPresentationNode.value.setValue(oInput.value);
- this.m_eElement.value = oInput.value;
- } else if (oUi) {
- oPresentationNode.value.setValue(oUi.item.value);
- this.m_eElement.value = oUi.item.value;
+ var isValidOption = oPresentationNode.isValidOption( oInput.value );
+
+ if ( isValidOption || oUi ) {
+ var presentationNodeValue = isValidOption ? oInput.value : oUi.item.value;
+
+ oPresentationNode.value.setValue( presentationNodeValue );
+ this.m_eElement.value = ( this.clearTextAfterValidInput ? '' : oPresentationNode.value.getFormattedValue());
}
};
JQueryAutoCompleteControl.prototype._valueChanged = function() {
- this.m_eElement.value = this.m_oPresentationNode.value.getValue();
+ this.m_eElement.value = this.m_oPresentationNode.value.getFormattedValue();
};
/**
* @private
*/
JQueryAutoCompleteControl.prototype.setOptions = function(mOptions) {
- if (mOptions && mOptions.openOnFocus !== undefined && mOptions.openOnFocus !== 'false') {
+ mOptions = mOptions || {};
+
+ if (mOptions.openOnFocus !== undefined && mOptions.openOnFocus !== 'false') {
this.m_bOpenOnFocus = true;
}
- if (mOptions && mOptions.appendTo !== undefined) {
+ if (mOptions.appendTo !== undefined) {
this.m_sAppendTo = mOptions.appendTo;
}
- if (mOptions && mOptions.minCharAmount !== undefined) {
+ if (mOptions.minCharAmount !== undefined) {
this.m_nMinCharAmount = mOptions.minCharAmount;
}
- if ( mOptions && mOptions.blurAfterClick !== undefined) {
+ if (mOptions.blurAfterClick !== undefined) {
this.m_bBlurAfterClick = mOptions.blurAfterClick;
}
+ if (mOptions.delay !== undefined) {
+ this.delay = mOptions.delay;
+ }
+ if (mOptions.clearTextAfterValidInput !== undefined) {
+ this.clearTextAfterValidInput = mOptions.clearTextAfterValidInput;
+ }
};
/**
* Destroy created listeners and jQuery autocomplete plugin
*/
JQueryAutoCompleteControl.prototype.destroy = function() {
+ // if onOpen is never called the control wouldn't be initialised, hence we must guard against that
+ if(this._viewOpened) {
+ this.m_jQueryInput.off('focus', this._onDocumentFocus);
+ jQuery( document.body ).off('mousewheel wheel', this._onScroll);
+ this.m_jQueryInput.autocomplete('destroy');
+ this.m_jQueryInput.off();
+ }
+
if (this._valueChangedListener) {
this.m_oPresentationNode.value.removeListener(this._valueChangedListener);
}
- if (this._viewOpened === true) {
- jQuery(this.m_eElement).autocomplete('destroy').off();
- }
-}
+
+ this._valueChangedListener = null;
+ this.m_jQueryInput = null;
+ this.m_eElement = null;
+};
module.exports = JQueryAutoCompleteControl;
diff --git a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/resources/html/test-form.html b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/resources/html/test-form.html
index 4049c0c63..a9cbbc572 100644
--- a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/resources/html/test-form.html
+++ b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/resources/html/test-form.html
@@ -13,7 +13,10 @@
-
+
+
+
+
@@ -32,9 +35,10 @@
-
-
-
-
+
+
+
+
+
diff --git a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/src-test/br/presenter/TestPresentationModel.js b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/src-test/br/presenter/TestPresentationModel.js
index 808a280df..d7e457ce8 100644
--- a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/src-test/br/presenter/TestPresentationModel.js
+++ b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/src-test/br/presenter/TestPresentationModel.js
@@ -49,7 +49,7 @@ TestPresentationModel = function()
this.labelValueSelectionField.visible.setValue(true);
this.jquerySelectionField = new AutoCompleteSelectionField("BB", {
- list: ["AA", "BB", "CC"],
+ list: ["AA", "BB", "CC", "FormatMe"],
getList: function(sTerm, fCallback) {
var pResult = [];
for (var i = 0; i < this.list.length; i++)
@@ -65,7 +65,13 @@ TestPresentationModel = function()
return ArrayUtility.inArray(this.list, sOption);
}
});
-
+
+ this.jquerySelectionField.value.addFormatter({
+ format: function (value) {
+ return value === "FormatMe" ? "Formatted" : value;
+ }
+ })
+
this.multiSelectBox = new MultiSelectionField(["a","b","c", "d"], ["a","c"]);
this.multiSelectBox.controlName.setValue("aMultiSelectionField");
diff --git a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/tests/control/selectionfield/JQueryAutoCompleteControlAdapterTest.js b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/tests/control/selectionfield/JQueryAutoCompleteControlAdapterTest.js
deleted file mode 100644
index 7e22fe5bf..000000000
--- a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/tests/control/selectionfield/JQueryAutoCompleteControlAdapterTest.js
+++ /dev/null
@@ -1,67 +0,0 @@
-(function() {
- var GwtTestRunner = require("br/test/GwtTestRunner");
- GwtTestRunner.initialize();
-
- describe("View to model interactions for JQueryAutoCompleteControlAdapter", function() {
- fixtures( require("br/presenter/PresenterFixtureFactory") );
-
- it("starts enabled and visible by default", function() {
- given("demo.viewOpened = true");
- then("demo.view.(#jqueryAutoCompleteBox).enabled = true");
- and("demo.view.(#jqueryAutoCompleteBox).isVisible = true");
- });
-
- it("has the correct initial value", function() {
- given("demo.viewOpened = true");
- then("demo.view.(#jqueryAutoCompleteBox).value = 'BB'");
- });
-
- it("correctly auto completes a valid input option", function() {
- given("demo.viewOpened = true");
- when("demo.model.jquerySelectionField.value => ''");
- and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'A'");
- then("demo.view.(#autocomplete-container li:eq(0)).text = 'AA'");
- });
-
- it("shows no options for invalid text", function() {
- given("demo.viewOpened = true");
- when("demo.model.jquerySelectionField.value => ''");
- and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'D'");
- then("demo.view.(#autocomplete-container li).count = '0'");
- });
-
- it("allows clicking on option to set the value", function() {
- given("demo.viewOpened = true");
- when("demo.model.jquerySelectionField.value => ''");
- and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'A'");
- and("demo.view.(#autocomplete-container li:eq(0) a).clicked => true");
- then("demo.model.jquerySelectionField.value = 'AA'");
- and("demo.view.(#jqueryAutoCompleteBox).value = 'AA'");
- });
-
- it("does not display any options if minCharAmount is set to 2", function() {
- given("demo.viewOpened = true");
- when("demo.model.jquerySelectionField.value => ''");
- and("demo.view.(#jqueryAutoCompleteBox2).typedValue => 'A'");
- then("demo.view.(#autocomplete-container2 li).count = '0'");
- });
-
- it("does display options if minCharAmount is set to 2 and typed text is at least 2 chars long", function() {
- given("demo.viewOpened = true");
- when("demo.model.jquerySelectionField.value => ''");
- and("demo.view.(#jqueryAutoCompleteBox2).typedValue => 'AA'");
- then("demo.view.(#autocomplete-container2 li:eq(0)).text = 'AA'");
- });
-
- it("does blur the input after selection is made by click if blurAfterClick is set to true", function() {
- given("demo.viewOpened = true");
- when("demo.model.jquerySelectionField.value => ''");
- and("demo.view.(#jqueryAutoCompleteBox3).typedValue => 'A'");
- and("demo.view.(#autocomplete-container li:eq(0) a).clicked => true");
- then("demo.model.jquerySelectionField.value = 'AA'");
- and("demo.view.(#jqueryAutoCompleteBox3).value = 'AA'");
- and("demo.view.(#jqueryAutoCompleteBox3).focused = false");
- });
-
- });
-})();
diff --git a/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/tests/control/selectionfield/JQueryAutoCompleteControlTest.js b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/tests/control/selectionfield/JQueryAutoCompleteControlTest.js
new file mode 100644
index 000000000..73acaa24d
--- /dev/null
+++ b/brjs-sdk/sdk/libs/javascript/br-presenter/test-acceptance/tests/control/selectionfield/JQueryAutoCompleteControlTest.js
@@ -0,0 +1,132 @@
+(function() {
+ var GwtTestRunner = require("br/test/GwtTestRunner");
+ GwtTestRunner.initialize();
+
+ describe("View to model interactions for JQueryAutoCompleteControlAdapter", function() {
+ fixtures( require("br/presenter/PresenterFixtureFactory") );
+
+ it("starts enabled and visible by default", function() {
+ given("demo.viewOpened = true");
+ then("demo.view.(#jqueryAutoCompleteBox).enabled = true");
+ and("demo.view.(#jqueryAutoCompleteBox).isVisible = true");
+ });
+
+ it("has the correct initial value", function() {
+ given("demo.viewOpened = true");
+ then("demo.view.(#jqueryAutoCompleteBox).value = 'BB'");
+ and("demo.view.(#jqueryAutoCompleteBox).doesNotHaveClass = 'autocomplete-menu-open'");
+ });
+
+ it("correctly auto completes a valid input option", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'A'");
+ then("demo.view.(#autocomplete-container li:eq(0)).text = 'AA'");
+ });
+
+ it("shows no options for invalid text", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'D'");
+ then("demo.view.(#autocomplete-container li).count = '0'");
+ });
+
+ it("allows clicking on option to set the value", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'A'");
+ and("demo.view.(#autocomplete-container li:eq(0) a).clicked => true");
+ then("demo.model.jquerySelectionField.value = 'AA'");
+ and("demo.view.(#jqueryAutoCompleteBox).value = 'AA'");
+ });
+
+ it("sets the formatted value to the textbox", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'F'");
+ and("demo.view.(#autocomplete-container li:eq(0) a).clicked => true");
+ then("demo.view.(#jqueryAutoCompleteBox).value = 'Formatted'");
+ });
+
+ it("hides the dropdown when the page is scrolled", function() {
+ given("test.continuesFrom = 'correctly auto completes a valid input option'");
+ when("test.page.(div:first).mouseWheel => '20'");
+ then("demo.view.(#autocomplete-container li).isVisible = false");
+ });
+
+ it("does not hide the dropdown when the menu is scrolled", function() {
+ given("test.continuesFrom = 'correctly auto completes a valid input option'");
+ when("demo.view.(#autocomplete-container .ui-menu-item:first).mouseWheel => '20'");
+ then("demo.view.(#autocomplete-container li).isVisible = true");
+ });
+
+ it("adds a class to the input and when it opens", function() {
+ given("test.continuesFrom = 'correctly auto completes a valid input option'");
+ then("demo.view.(#jqueryAutoCompleteBox).hasClass = 'autocomplete-menu-open'");
+ });
+
+ it("removes a class from the input when it closes", function() {
+ given("test.continuesFrom = 'hides the dropdown when the page is scrolled'");
+ then("demo.view.(#jqueryAutoCompleteBox).doesNotHaveClass = 'autocomplete-menu-open'");
+ });
+
+ it("does not display any options if minCharAmount is set to 2", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox2).typedValue => 'A'");
+ then("demo.view.(#autocomplete-container2 li).count = '0'");
+ });
+
+ it("does display options if minCharAmount is set to 2 and typed text is at least 2 chars long", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox2).typedValue => 'AA'");
+ then("demo.view.(#autocomplete-container2 li:eq(0)).text = 'AA'");
+ });
+
+ it("does not blur the input after selection if blurAfterClick is not provided", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox).typedValue => 'A'");
+ and("demo.view.(#autocomplete-container li:eq(0) a).clicked => true");
+ then("demo.model.jquerySelectionField.value = 'AA'");
+ and("demo.view.(#jqueryAutoCompleteBox).value = 'AA'");
+ and("demo.view.(#jqueryAutoCompleteBox).focused = true");
+ });
+
+ it("does blur the input after selection is made by click if blurAfterClick is set to true", function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox3).typedValue => 'A'");
+ and("demo.view.(#autocomplete-container3 li:eq(0) a).clicked => true");
+ then("demo.model.jquerySelectionField.value = 'AA'");
+ and("demo.view.(#jqueryAutoCompleteBox3).value = 'AA'");
+ and("demo.view.(#jqueryAutoCompleteBox3).focused = false");
+ });
+
+ it("does not show the menu immediately when a delay option is given", function() {
+ given("demo.viewOpened = true");
+ and("time.timeMode = 'Manual'");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox4).typedValue => 'A'");
+ then("demo.view.(#autocomplete-container4 li).count = '0'");
+ });
+
+ it("shows the menu after some time when a delay option is given", function() {
+ given("test.continuesFrom = 'does not show the menu immediately when a delay option is given'");
+ when("time.passedBy => 200");
+ then("demo.view.(#autocomplete-container4 li).isVisible = true");
+ and("demo.view.(#autocomplete-container4 li:eq(0)).text = 'AA'");
+ });
+
+ it('clears the textbox after a valid option was chosen', function() {
+ given("demo.viewOpened = true");
+ when("demo.model.jquerySelectionField.value => ''");
+ and("demo.view.(#jqueryAutoCompleteBox5).typedValue => 'A'");
+ and("demo.view.(#autocomplete-container5 li:eq(0) a).clicked => true");
+ then("demo.model.jquerySelectionField.value = 'AA'");
+ and("demo.view.(#jqueryAutoCompleteBox5).value = ''");
+ });
+
+ });
+})();
diff --git a/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/ViewFixture.js b/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/ViewFixture.js
index 9adc87155..6b63620d7 100644
--- a/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/ViewFixture.js
+++ b/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/ViewFixture.js
@@ -71,6 +71,7 @@ function ViewFixture(viewSelector) {
var MouseOut = require('br/test/viewhandler/MouseOut');
var MouseOver = require('br/test/viewhandler/MouseOver');
var MouseUp = require('br/test/viewhandler/MouseUp');
+ var MouseWheel = require('br/test/viewhandler/MouseWheel');
var OnKeyUp = require('br/test/viewhandler/OnKeyUp');
var Options = require('br/test/viewhandler/Options');
var Readonly = require('br/test/viewhandler/Readonly');
@@ -112,6 +113,7 @@ function ViewFixture(viewSelector) {
mouseOut: new MouseOut(),
mouseOver: new MouseOver(),
mouseUp: new MouseUp(),
+ mouseWheel: new MouseWheel(),
onKeyUp: new OnKeyUp(),
options: new Options(),
readonly: new Readonly(),
diff --git a/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/viewhandler/MouseWheel.js b/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/viewhandler/MouseWheel.js
new file mode 100644
index 000000000..5092fcc5a
--- /dev/null
+++ b/brjs-sdk/sdk/libs/javascript/br-test/src/br/test/viewhandler/MouseWheel.js
@@ -0,0 +1,39 @@
+'use strict';
+
+/**
+ * @module br/test/viewhandler/MouseWheel
+ */
+
+var br = require('br/Core');
+var Errors = require('br/Errors');
+var ViewFixtureHandler = require('br/test/viewhandler/ViewFixtureHandler');
+var Utils = require('br/test/Utils');
+
+/**
+ * @class
+ * @alias module:br/test/viewhandler/MouseWheel
+ * @implements module:br/test/viewhandler/ViewFixtureHandler
+ *
+ * @classdesc
+ * MouseWheel
instances of ViewFixtureHandler
can be used to trigger mousewheel
event for a view element.
+ * Example usage:
+ *
+ * when("test.page.(#aRealButton).mouseWheel => true");
+ */
+function MouseWheel() {
+}
+br.implement(MouseWheel, ViewFixtureHandler);
+
+MouseWheel.prototype.set = function(eElement, mValues) {
+ var event = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
+ document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
+ "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
+
+ Utils.fireMouseEvent(eElement, 'wheel', mValues);
+};
+
+MouseWheel.prototype.get = function(eElement) {
+ throw new Errors.InvalidTestError("The mouseWheel event cannot be used in a doGiven or doThen");
+};
+
+module.exports = MouseWheel;