Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Autoselect for HTML Text Input #272

Closed
wants to merge 1 commit into from

2 participants

@fab-b
Collaborator

No description provided.

@fab-b fab-b referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@fab-b fab-b referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@fab-b fab-b referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@fab-b fab-b referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@fab-b fab-b referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@divdavem divdavem was assigned
src/aria/html/TextInput.js
@@ -100,7 +118,15 @@
*/
this._reactOnType = this._registerType(cfg.on, context);
- this._registerBlur(cfg.on, context);
+ this._registerListeners(cfg, context);
+
+ /**
+ * Flag set to false after first focus, and set back to true after a blur. Used for the autoselect behaviour.
+ * This value is true when the field receives focus for the first time (user action) and false when the focus is
+ * giveng programmatically by the controller
@divdavem Collaborator

Should be 'given' instead of 'giveng'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/aria/html/TextInput.js
((10 lines not shown))
+ if (this._firstFocus) {
+ // this allow to click again and put the cursor at a given
+ // position
+ this._firstFocus = false;
+ var field = this._domElt;
+ var start = 0;
+ var end = (field.value.length) ? field.value.length : 0;
+ if (end) {
+ aria.utils.Caret.setCaretPosition(field, start, end);
+ }
+ }
+ },
+
+ /**
+ * Add special listeners on top of the ones specified in configuration.
+ * @param {aria.html.beans.TextInputCfg.Properties} listeners On listeners taken from the widget configuration.
@divdavem Collaborator

JSDoc has to be updated: the first parameter is now the whole configuration and not only 'On' listeners.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/aria/html/beans/TextInputCfg.js
@@ -53,6 +53,11 @@ Aria.beanDefinitions({
$type : "json:Boolean",
$description : "Whether the input field should be of type password.",
$default : false
+ },
+ "autoselect" : {
+ $type : "json:Boolean",
+ $description : "Autoselect for the input field.",
@divdavem Collaborator

I think the description should describe the feature more precisely. For example: "If true, the whole field is automatically selected when the user clicks on it."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
src/aria/utils/Caret.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Amadeus s.a.s. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
+ * file except in compliance with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific language governing permissions and limitations under the
+ * License.
+ */
@divdavem Collaborator

There seems to be a formatting issue with the license header.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@divdavem divdavem referenced this pull request from a commit in divdavem/ariatemplates
@fab-b fab-b feat #272 Autoselect feature for HTML text input bbed68b
@divdavem
Collaborator

:+1:
Integrated in bbed68b.

@divdavem divdavem closed this
@susant123 susant123 referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 14, 2012
  1. @fab-b
This page is out of date. Refresh to see the latest.
View
2  src/aria/html/Element.js
@@ -111,7 +111,7 @@
if (eventListeners.hasOwnProperty(listener)) {
hasListeners = true;
- eventListeners[listener] = this.$normCallback.call(this._context, eventListeners[listener]);
+ eventListeners[listener] = this.$normCallback.call(this._context._tpl, eventListeners[listener]);
}
}
View
68 src/aria/html/TextInput.js
@@ -70,18 +70,36 @@
var newValue = this._transform(bind.transform, event.target.getValue(), "fromWidget");
aria.utils.Json.setValue(bind.inside, bind.to, newValue, bind.cb);
+ this._firstFocus = true;
+
if (blurCallback) {
blurCallback.fn.call(blurCallback.scope, event, blurCallback.args);
}
}
/**
+ * This is to implement the autoselect.
+ * @param {aria.DomEvent} event focus event
+ * @param {aria.core.CfgBeans.Callback} clickCallback On click callback
+ * @private
+ */
+ function clickBinding (event, clickCallback) {
+ if (this._cfg.autoselect) {
+ this._autoselect();
+ }
+
+ if (clickCallback) {
+ clickCallback.fn.call(clickCallback.scope, event, clickCallback.args);
+ }
+ }
+
+ /**
* TextInput widget. Bindable widget providing bi-directional bind of 'value' and on 'type' event callback.
*/
Aria.classDefinition({
$classpath : "aria.html.TextInput",
$extends : "aria.html.Element",
- $dependencies : ["aria.html.beans.TextInputCfg"],
+ $dependencies : ["aria.html.beans.TextInputCfg", "aria.utils.Caret"],
$statics : {
INVALID_USAGE : "Widget %1 can only be used as a %2."
},
@@ -100,7 +118,15 @@
*/
this._reactOnType = this._registerType(cfg.on, context);
- this._registerBlur(cfg.on, context);
+ this._registerListeners(cfg, context);
+
+ /**
+ * Flag set to false after first focus, and set back to true after a blur. Used for the autoselect
+ * behaviour. This value is true when the field receives focus for the first time (user action) and false
+ * when the focus is given programmatically by the controller
+ * @type Boolean
+ */
+ this._firstFocus = true;
this.$Element.constructor.call(this, cfg, context, line);
},
@@ -200,13 +226,31 @@
},
/**
- * Convert the special event type into a keydown event listener.
- * @param {Object} listeners On listeners taken from the widget configuration.
+ * If enabled, autoselect the widget text setting the caret position to the whole input value.
+ * @protected
+ */
+ _autoselect : function () {
+ if (this._firstFocus) {
+ // this allow to click again and put the cursor at a given
+ // position
+ this._firstFocus = false;
+ var field = this._domElt;
+ var start = 0;
+ var end = (field.value.length) ? field.value.length : 0;
+ if (end) {
+ aria.utils.Caret.setCaretPosition(field, start, end);
+ }
+ }
+ },
+
+ /**
+ * Add special listeners on top of the ones specified in configuration.
+ * @param {aria.html.beans.TextInputCfg.Properties} cfg Widget configuration.
* @param {aria.templates.TemplateCtxt} context Reference of the template context.
- * @return {Boolean} Whether the keydown events should be converted back to type events.
* @protected
*/
- _registerBlur : function (listeners, context) {
+ _registerListeners : function (cfg, context) {
+ var listeners = cfg.on;
var normalized;
if (listeners.blur) {
@@ -218,6 +262,18 @@
scope : this,
args : normalized
};
+
+ if (cfg.autoselect) {
+ if (listeners.click) {
+ normalized = this.$normCallback.call(context._tpl, listeners.click);
+ }
+
+ listeners.click = {
+ fn : clickBinding,
+ scope : this,
+ args : normalized
+ };
+ }
}
}
View
5 src/aria/html/beans/TextInputCfg.js
@@ -53,6 +53,11 @@ Aria.beanDefinitions({
$type : "json:Boolean",
$description : "Whether the input field should be of type password.",
$default : false
+ },
+ "autoselect" : {
+ $type : "json:Boolean",
+ $description : "Autoselect for the input field. If true, the whole text inside the field is automatically selected when the user clicks on it.",
+ $default : false
}
}
}
View
76 src/aria/utils/Caret.js
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Amadeus s.a.s.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @class aria.utils.Caret Utilities for the caret
+ * @singleton
+ */
+Aria.classDefinition({
+ $classpath : 'aria.utils.Caret',
+ $singleton : true,
+ $prototype : {
+ /**
+ * Return the caret position of the HTML element
+ * @param {HTMLElement} element The html element
+ * @return {Object} The caret position (start and end)
+ */
+ getCaretPosition : function (element) {
+ var pos = {
+ start : 0,
+ end : 0
+ };
+
+ if ("selectionStart" in element) {
+ // w3c standard, available in all but IE<9
+ pos.start = element.selectionStart;
+ pos.end = element.selectionEnd;
+ } else {
+ // old IE support
+ var document = Aria.$window.document;
+ if (document.selection) {
+ var sel = document.selection.createRange();
+ var initialLength = sel.text.length;
+ sel.moveStart('character', -element.value.length);
+ var x = sel.text.length;
+ pos.start = x - initialLength;
+ pos.end = x;
+ }
+ }
+
+ return pos;
+ },
+
+ /**
+ * Set the caret position of the HTML element
+ * @param {HTMLElement} element The html element
+ * @param {Number} start The starting caret position
+ * @param {Number} end The ending caret position
+ */
+ setCaretPosition : function (element, start, end) {
+ if ("selectionStart" in element) {
+ element.selectionStart = start;
+ element.selectionEnd = end;
+ } else {
+ var document = Aria.$window.document;
+ if (document.selection) {
+ var range = element.createTextRange();
+ range.moveStart('character', start);
+ range.moveEnd('character', -element.value.length + end);
+ range.select();
+ }
+ }
+ }
+ }
+});
View
40 src/aria/widgets/form/TextInput.js
@@ -20,7 +20,7 @@ Aria.classDefinition({
$classpath : "aria.widgets.form.TextInput",
$extends : "aria.widgets.form.InputWithFrame",
$dependencies : ["aria.utils.Function", "aria.utils.Data", "aria.utils.String",
- "aria.widgets.environment.WidgetSettings"],
+ "aria.widgets.environment.WidgetSettings", "aria.utils.Caret"],
$css : ["aria.widgets.form.TextInputStyle"],
/**
* TextInput constructor
@@ -507,29 +507,7 @@ Aria.classDefinition({
return null;
}
var ctrl = this.getTextInputField();
- var pos = {
- start : 0,
- end : 0
- };
-
- if ("selectionStart" in ctrl) {
- // w3c standard, available in all but IE<9
- pos.start = ctrl.selectionStart;
- pos.end = ctrl.selectionEnd;
- } else {
- // old IE support
- var document = Aria.$window.document;
- if (document.selection) {
- var sel = document.selection.createRange();
- var initialLength = sel.text.length;
- sel.moveStart('character', -ctrl.value.length);
- var x = sel.text.length;
- pos.start = x - initialLength;
- pos.end = x;
- }
- }
-
- return pos;
+ return aria.utils.Caret.getCaretPosition(ctrl);
},
/**
@@ -543,19 +521,7 @@ Aria.classDefinition({
}
var ctrl = this.getTextInputField();
-
- if ("selectionStart" in ctrl) {
- ctrl.selectionStart = start;
- ctrl.selectionEnd = end;
- } else {
- var document = Aria.$window.document;
- if (document.selection) {
- var range = ctrl.createTextRange();
- range.moveStart('character', start);
- range.moveEnd('character', -ctrl.value.length + end);
- range.select();
- }
- }
+ aria.utils.Caret.setCaretPosition(ctrl, start, end);
},
/**
View
34 test/aria/html/ElementEventsTest.js
@@ -67,7 +67,7 @@ Aria.classDefinition({
oneEvent = events[1];
this.assertEquals(oneEvent.type, "keydown", "Second event should be a keydown, got " + oneEvent.type);
- this.assertEquals(oneEvent.context, "Element", "Second event should have context Element, got "
+ this.assertEquals(oneEvent.context, "TplContext", "Second event should have context Element, got "
+ oneEvent.context);
this.assertEquals(oneEvent.tagName, "DIV", "Second event should happen on a DIV, got "
+ oneEvent.tagName);
@@ -79,7 +79,7 @@ Aria.classDefinition({
oneEvent = events[2];
this.assertEquals(oneEvent.type, "mousedown", "Third event should be a mousedown, got " + oneEvent.type);
- this.assertEquals(oneEvent.context, "Element", "Third event should have context Element, got "
+ this.assertEquals(oneEvent.context, "TplContext", "Third event should have context Element, got "
+ oneEvent.context);
this.assertEquals(oneEvent.tagName, "SPAN", "Third event should happen on a SPAN, got "
+ oneEvent.tagName);
@@ -145,7 +145,7 @@ Aria.classDefinition({
keydown : function (evt) {
events.push({
type : evt.type,
- context : this.tplClasspath,
+ context : this.context,
tagName : evt.target.tagName,
key : "tokyo-keydown",
param : "missing",
@@ -157,7 +157,10 @@ Aria.classDefinition({
};
return new aria.html.Element(first, {
- tplClasspath : "Element"
+ tplClasspath : "Element",
+ _tpl : {
+ context : "TplContext"
+ }
});
},
@@ -198,16 +201,19 @@ Aria.classDefinition({
return new aria.html.Element(second, {
tplClasspath : "Element",
- functionOnTemplateContext : function (evt) {
- events.push({
- type : evt.type,
- context : this.tplClasspath,
- tagName : evt.target.tagName,
- key : "osaka-mousedown",
- param : "missing",
- isTargetWrapped : !!evt.target.$DomElementWrapper,
- name : evt.target.getAttribute("name")
- });
+ _tpl : {
+ functionOnTemplateContext : function (evt) {
+ events.push({
+ type : evt.type,
+ context : this.context,
+ tagName : evt.target.tagName,
+ key : "osaka-mousedown",
+ param : "missing",
+ isTargetWrapped : !!evt.target.$DomElementWrapper,
+ name : evt.target.getAttribute("name")
+ });
+ },
+ context : "TplContext"
}
});
},
View
1  test/aria/html/textinput/TextInputTestSuite.js
@@ -24,5 +24,6 @@ Aria.classDefinition({
this.addTests("test.aria.html.textinput.TextInputOnTypeTest");
this.addTests("test.aria.html.textinput.TextInputPasswordTest");
this.addTests("test.aria.html.textinput.focus.FocusTestCase");
+ this.addTests("test.aria.html.textinput.autoselect.AutoselectTestCase");
}
});
View
135 test/aria/html/textinput/autoselect/AutoselectTestCase.js
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2012 Amadeus s.a.s.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Aria.classDefinition({
+ $classpath : "test.aria.html.textinput.autoselect.AutoselectTestCase",
+ $extends : "aria.jsunit.TemplateTestCase",
+ $dependencies : ["aria.html.TextInput", "aria.utils.SynEvents", "aria.utils.Dom"],
+ $constructor : function () {
+ this.$TemplateTestCase.constructor.call(this);
+ this.element = null;
+ },
+ $destructor : function () {
+ this.element = null;
+ },
+ $prototype : {
+ runTemplateTest : function () {
+ var document = Aria.$window.document;
+ var inputs = document.getElementsByTagName("input");
+ this.element = inputs[0];
+ this.secondElement = inputs[1];
+
+ aria.utils.SynEvents.click(this.element, {
+ fn : this.afterFirstClick,
+ scope : this
+ });
+ },
+
+ afterFirstClick : function () {
+ var caretPos = aria.utils.Caret.getCaretPosition(this.element);
+
+ this.assertEquals(caretPos.start, 0, "The start pos of caret is not zero");
+ this.assertEquals(caretPos.end, 0, "The end pos of caret is not zero");
+
+ aria.utils.SynEvents.type(this.element, "brazil", {
+ fn : this.afterType,
+ scope : this
+ });
+ },
+
+ afterType : function () {
+ var caretPos = aria.utils.Caret.getCaretPosition(this.element);
+
+ this.assertEquals(caretPos.start, this.element.value.length, "The start pos of caret is not at the end of the word typed");
+ this.assertEquals(caretPos.end, this.element.value.length, "The end pos of caret is not at the end of the word typed");
+
+ this.assertEquals(this.element.value, "brazil", "The value of input text is not brazil");
+
+ var outside = aria.utils.Dom.getElementById("outsideDiv");
+
+ aria.utils.SynEvents.click(outside, {
+ fn : this.afterSecondClick,
+ scope : this
+ });
+ },
+
+ afterSecondClick : function () {
+ aria.utils.SynEvents.click(this.element, {
+ fn : this.afterThirdClick,
+ scope : this
+ });
+ },
+
+ afterThirdClick : function () {
+ this.assertEquals(this.templateCtxt._tpl.data.click, 2, "Click callback set in the widget configuration has not been called");
+
+ var caretPos = aria.utils.Caret.getCaretPosition(this.element);
+ this.assertEquals(caretPos.start, 0, "The start pos of caret is not zero");
+ this.assertEquals(caretPos.end, this.element.value.length, "The end pos of caret is not at the end of the word typed");
+ this.assertEquals(this.element.value, "brazil", "The value of input text is not brazil");
+
+ aria.utils.SynEvents.click(this.secondElement, {
+ fn : this.afterFirstClickTwo,
+ scope : this
+ });
+ },
+
+ afterFirstClickTwo : function () {
+ var caretPos = aria.utils.Caret.getCaretPosition(this.secondElement);
+
+ this.assertEquals(caretPos.start, 0, "The start pos of caret is not zero");
+ this.assertEquals(caretPos.end, 0, "The end pos of caret is not zero");
+
+ aria.utils.SynEvents.type(this.secondElement, "argentina", {
+ fn : this.afterTypeTwo,
+ scope : this
+ });
+ },
+
+ afterTypeTwo : function () {
+ var caretPos = aria.utils.Caret.getCaretPosition(this.secondElement);
+
+ this.assertEquals(caretPos.start, this.secondElement.value.length, "The start pos of caret is not at the end of the word typed");
+ this.assertEquals(caretPos.end, this.secondElement.value.length, "The end pos of caret is not at the end of the word typed");
+
+ this.assertEquals(this.secondElement.value, "argentina", "The value of input text is not argentina");
+
+ var outside = aria.utils.Dom.getElementById("outsideDiv");
+
+ aria.utils.SynEvents.click(outside, {
+ fn : this.afterSecondClickTwo,
+ scope : this
+ });
+ },
+
+ afterSecondClickTwo : function () {
+ aria.utils.SynEvents.click(this.secondElement, {
+ fn : this.afterThirdClickTwo,
+ scope : this
+ });
+ },
+
+ afterThirdClickTwo : function () {
+ // check that click callback declared in the widget configuration is called
+ this.assertEquals(this.templateCtxt._tpl.data.clickNoAutoselect, 2, "Click callback set in the widget configuration has not been called");
+
+ var caretPos = aria.utils.Caret.getCaretPosition(this.secondElement);
+ this.assertEquals(caretPos.start - caretPos.end, 0, "Autoselect false has not been taken into account");
+ this.assertEquals(this.secondElement.value, "argentina", "The value of input text is not argentina");
+
+ this.end();
+ }
+ }
+});
View
61 test/aria/html/textinput/autoselect/AutoselectTestCaseTpl.tpl
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2012 Amadeus s.a.s.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+{Template {
+ $classpath : "test.aria.html.textinput.autoselect.AutoselectTestCaseTpl",
+ $hasScript: true,
+ $wlibs : {
+ html : "aria.html.HtmlLibrary"
+ }
+}}
+
+{macro main()}
+
+<div id="testForTextInputAutoselect">
+
+ {@html:TextInput {
+ id: "texttest",
+ autoselect: true,
+ on : {
+ type : "textType",
+ click : "textClick"
+ },
+ bind : {
+ value: {
+ inside: data,
+ to: "location"
+ }
+ }
+ }/}
+
+ {@html:TextInput {
+ id: "texttestOne",
+ on : {
+ type : "textType",
+ click : "textClickWithoutAutoselect"
+ },
+ bind : {
+ value: {
+ inside: data,
+ to: "departure"
+ }
+ }
+ }/}
+
+</div>
+
+<div id="outsideDiv">&nbsp;</div>
+{/macro}
+{/Template}
View
40 test/aria/html/textinput/autoselect/AutoselectTestCaseTplScript.js
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Amadeus s.a.s.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+Aria.tplScriptDefinition({
+ $classpath : "test.aria.html.textinput.autoselect.AutoselectTestCaseTplScript",
+ $prototype : {
+ $dataReady : function () {
+ this.data = {
+ location : '',
+ departure : '',
+ click : 0,
+ clickNoAutoselect : 0
+ };
+ },
+
+ textType : function (value) {
+ return;
+ },
+
+ textClick : function () {
+ this.data.click++;
+ },
+
+ textClickWithoutAutoselect : function () {
+ this.data.clickNoAutoselect++;
+ }
+ }
+});
Something went wrong with that request. Please try again.