Author: max
Date: 2007-12-19 19:33:49 -0800 (Wed, 19 Dec 2007)
New Revision: 7626
Modified:
openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js
openlaszlo/trunk/test/lztest/lztest-text.lzx
Log:
Change 20071217-maxcarlson-V by [EMAIL PROTECTED] on 2007-12-17 18:14:44 PST
in /Users/maxcarlson/openlaszlo/trunk
for http://svn.openlaszlo.org/openlaszlo/trunk
Summary: Add seuuport for setting/getting inputtext selection in DHTML
New Features:
Bugs Fixed: LPP-4106 - LzText getSelectionPosition, getSelectionSize not
implemented in DHTML
Technical Reviewer: promanik
QA Reviewer: ptw
Doc Reviewer: (pending)
Documentation:
Release Notes:
Details: lztest-text.lzx - Changed selection tests to use inputtext.
LzSprite.js - Clean up quirks setting, add text_selection_use_range for IE.
Fix _parent braino.
LzInputTextSprite.js - Add setSelection() and getSelectionStart() and
getSelectionEnd.
Tests: lztest-text.lzx now passes all tests in test4() - selection. Tested in
Firefox, Safari and IE 7.
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
2007-12-19 22:55:04 UTC (rev 7625)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
2007-12-20 03:33:49 UTC (rev 7626)
@@ -284,7 +284,7 @@
this.__LzInputDiv.maxLength = val;
}
-LzInputTextSprite.prototype.select = function (start, end){
+LzInputTextSprite.prototype.select = function (){
this._cancelblur = true;
this.__show();
this.__LzInputDiv.focus();
@@ -295,8 +295,254 @@
//Debug.write('select', this.uid, LzKeyboardKernel.__cancelKeys);
}
-LzInputTextSprite.prototype.setSelection = LzInputTextSprite.prototype.select;
+LzInputTextSprite.prototype.setSelection = function (start, end){
+ if (end == null) {
+ end = start;
+ }
+ this._cancelblur = true;
+ this.__show();
+ LzInputTextSprite.__lastfocus = this;
+ if (this.quirks['text_selection_use_range']) {
+ var range = this.__LzInputDiv.createTextRange();
+
+ // look for leading \r\n
+ var val = this.__LzInputDiv.value;
+
+ if (start > end){
+ var st = start;
+ start = end;
+ end = st;
+ }
+
+ if(this.multiline) {
+ var offset = 0;
+ // account for leading \r\n
+ var startcounter = 0;
+ while (offset < start) {
+ offset = val.indexOf('\r\n', offset + 2);
+ if (offset == -1) break;
+ startcounter++;
+ }
+ var midcounter = 0;
+ while (offset < end) {
+ offset = val.indexOf('\r\n', offset + 2);
+ if (offset == -1) break;
+ midcounter++;
+ }
+ var endcounter = 0;
+ while (offset < val.length) {
+ offset = val.indexOf('\r\n', offset + 2);
+ if (offset == -1) break;
+ endcounter++;
+ }
+
+ var tl = range.text.length;
+ var st = start;
+ var ed = end - val.length + startcounter + midcounter + endcounter
+ 1;
+
+ //if (endcounter) endcounter += startcounter;
+ //alert (startcounter + ', ' + midcounter + ', ' + endcounter + ',
' + st + ', ' + ed);
+ } else {
+ var st = start;
+ var ed = end - range.text.length;
+ }
+
+ range.moveStart("character", st);
+ range.moveEnd("character", ed);
+ range.select();
+ //this.__LzInputDiv.range = range;
+
//setTimeout('LzInputTextSprite.__lastfocus.__LzInputDiv.range.select()', 50);
+ //this.__LzInputDiv.focus();
+ } else {
+ this.__LzInputDiv.setSelectionRange(start, end);
+ }
+ this.__LzInputDiv.focus();
+
+ if (window['LzKeyboardKernel']) LzKeyboardKernel.__cancelKeys = false;
+}
+
+LzInputTextSprite.prototype.getSelectionPosition = function (){
+ if (! this.__shown || this.disabled == true) return -1;
+ if (this.quirks['text_selection_use_range']) {
+ if (this.multiline) {
+ var p = this._getTextareaSelection();
+ } else {
+ var p = this._getTextSelection();
+ }
+
+ if (p) {
+ return p.start;
+ } else {
+ return -1;
+ }
+ } else {
+ return this.__LzInputDiv.selectionStart;
+ }
+}
+
+LzInputTextSprite.prototype.getSelectionSize = function (){
+ if (! this.__shown || this.disabled == true) return -1;
+ if (this.quirks['text_selection_use_range']) {
+ if (this.multiline) {
+ var p = this._getTextareaSelection();
+ } else {
+ var p = this._getTextSelection();
+ }
+ if (p) {
+ return p.end - p.start;
+ } else {
+ return -1;
+ }
+ } else {
+ return this.__LzInputDiv.selectionEnd -
this.__LzInputDiv.selectionStart;
+ }
+}
+
+if (LzSprite.prototype.quirks['text_selection_use_range']) {
+LzInputTextSprite.prototype._getTextSelection = function (){
+ this.__LzInputDiv.focus();
+
+ var range = document.selection.createRange();
+ var bookmark = range.getBookmark();
+
+ var originalContents = contents = this.__LzInputDiv.value;
+ do {
+ var marker = "~~~" + Math.random() + "~~~";
+ } while (contents.indexOf(marker) != -1)
+
+ var parent = range.parentElement();
+ if (parent == null || ! (parent.type == "text" || parent.type ==
"textarea")) {
+ return;
+ }
+ range.text = marker + range.text + marker;
+ contents = this.__LzInputDiv.value;
+
+ var result = {};
+ result.start = contents.indexOf(marker);
+ contents = contents.replace(marker, "");
+ result.end = contents.indexOf(marker);
+
+ this.__LzInputDiv.value = originalContents;
+ range.moveToBookmark(bookmark);
+ range.select();
+
+ return result;
+}
+
+LzInputTextSprite.prototype._getTextareaSelection = function (){
+ var textarea = this.__LzInputDiv;
+ var selection_range = document.selection.createRange().duplicate();
+
+ if (selection_range.parentElement() == textarea) { // Check that the
selection is actually in our textarea
+ // Create three ranges, one containing all the text before the selection,
+ // one containing all the text in the selection (this already exists), and
one containing all
+ // the text after the selection.
+ var before_range = document.body.createTextRange();
+ before_range.moveToElementText(textarea); // Selects
all the text
+ before_range.setEndPoint("EndToStart", selection_range); // Moves the
end where we need it
+
+ var after_range = document.body.createTextRange();
+ after_range.moveToElementText(textarea); // Selects
all the text
+ after_range.setEndPoint("StartToEnd", selection_range); // Moves the
start where we need it
+
+ var before_finished = false, selection_finished = false, after_finished =
false;
+ var before_text, untrimmed_before_text, selection_text,
untrimmed_selection_text, after_text, untrimmed_after_text;
+
+ // Load the text values we need to compare
+ before_text = untrimmed_before_text = before_range.text;
+ selection_text = untrimmed_selection_text = selection_range.text;
+ after_text = untrimmed_after_text = after_range.text;
+
+ // Check each range for trimmed newlines by shrinking the range by 1
character and seeing
+ // if the text property has changed. If it has not changed then we know
that IE has trimmed
+ // a \r\n from the end.
+ do {
+ if (!before_finished) {
+ if (before_range.compareEndPoints("StartToEnd", before_range) == 0) {
+ before_finished = true;
+ } else {
+ before_range.moveEnd("character", -1)
+ if (before_range.text == before_text) {
+ untrimmed_before_text += "\r\n";
+ } else {
+ before_finished = true;
+ }
+ }
+ }
+ if (!selection_finished) {
+ if (selection_range.compareEndPoints("StartToEnd", selection_range) ==
0) {
+ selection_finished = true;
+ } else {
+ selection_range.moveEnd("character", -1)
+ if (selection_range.text == selection_text) {
+ untrimmed_selection_text += "\r\n";
+ } else {
+ selection_finished = true;
+ }
+ }
+ }
+ if (!after_finished) {
+ if (after_range.compareEndPoints("StartToEnd", after_range) == 0) {
+ after_finished = true;
+ } else {
+ after_range.moveEnd("character", -1)
+ if (after_range.text == after_text) {
+ untrimmed_after_text += "\r\n";
+ } else {
+ after_finished = true;
+ }
+ }
+ }
+
+ } while ((!before_finished || !selection_finished || !after_finished));
+
+ // Untrimmed success test to make sure our results match what is actually
in the textarea
+ // This can be removed once you're confident it's working correctly
+ var untrimmed_text = untrimmed_before_text + untrimmed_selection_text +
untrimmed_after_text;
+ var untrimmed_successful = false;
+ if (textarea.value == untrimmed_text) {
+ untrimmed_successful = true;
+ }
+ // ** END Untrimmed success test
+
+ var startPoint = untrimmed_before_text.length;
+ var endPoint = startPoint + untrimmed_selection_text.length;
+ var selected_text = untrimmed_selection_text;
+
+ //alert("Start Index: " + startPoint + "\nEnd Index: " + endPoint +
"\nSelected Text\n'" + selected_text + "'");
+
+ // account for leading \r\n
+ var val = this.__LzInputDiv.value;
+ var offset = 0;
+ var startcounter = 0;
+ while (offset < startPoint) {
+ offset = val.indexOf('\r\n', offset + 2);
+ if (offset == -1) break;
+ startcounter++;
+ }
+ var midcounter = 0;
+ while (offset < endPoint) {
+ offset = val.indexOf('\r\n', offset + 2);
+ if (offset == -1) break;
+ midcounter++;
+ }
+ var endcounter = 0;
+ while (offset < val.length) {
+ offset = val.indexOf('\r\n', offset + 2);
+ if (offset == -1) break;
+ endcounter++;
+ }
+
+ startPoint -= startcounter;
+ endPoint -= (midcounter + startcounter);
+
+ //Debug.write(startcounter + ', ' + midcounter + ', ' + endcounter + ', '
+ startPoint + ', ' + endPoint);
+ return {start: startPoint, end: endPoint};
+ }
+}
+}
+
LzInputTextSprite.prototype.deselect = function (){
this._cancelfocus = true;
this.__hide();
Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js 2007-12-19
22:55:04 UTC (rev 7625)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js 2007-12-20
03:33:49 UTC (rev 7626)
@@ -225,6 +225,7 @@
,set_height_for_multiline_inputtext: false
,ie_opacity: false
,text_measurement_use_insertadjacenthtml: false
+ ,text_selection_use_range: false
}
LzSprite.prototype.capabilities = {
@@ -243,89 +244,92 @@
LzSprite.prototype.__updateQuirks = function(){
if (window['Lz'] && Lz.__BrowserDetect) {
Lz.__BrowserDetect.init();
- if (this.quirks['inner_html_strips_newlines'] == true) {
+ var quirks = this.quirks;
+
+ if (quirks['inner_html_strips_newlines'] == true) {
LzSprite.prototype.inner_html_strips_newlines_re = RegExp('$',
'mg');
}
// Divs intercept clicks if physically placed on top of an element
// that's not a parent. See LPP-2680.
// off for now
- //this.quirks['fix_clickable'] = true;
+ //quirks['fix_clickable'] = true;
if (Lz.__BrowserDetect.isIE) {
if (Lz.__BrowserDetect.version < 7) {
// Provide IE PNG/opacity support
- this.quirks['ie_alpha_image_loader'] = true;
+ quirks['ie_alpha_image_loader'] = true;
} else {
- this.quirks['invisible_parent_image_sizing_fix'] = true;
+ quirks['invisible_parent_image_sizing_fix'] = true;
}
- this.quirks['ie_opacity'] = true;
+ quirks['ie_opacity'] = true;
// IE DOM leak prevention
- this.quirks['ie_leak_prevention'] = true;
+ quirks['ie_leak_prevention'] = true;
// Use images to force click tree to work in IE
- this.quirks['fix_ie_clickable'] = true;
+ quirks['fix_ie_clickable'] = true;
// workaround for IE refusing to respect divs with small heights
when
// no image is attached
- this.quirks['fix_ie_background_height'] = true;
+ quirks['fix_ie_background_height'] = true;
// workaround for IE not supporting ' in innerHTML
- this.quirks['inner_html_no_entity_apos'] = true;
+ quirks['inner_html_no_entity_apos'] = true;
// workaround for IE not supporting clip in divs containing
inputtext
- this.quirks['inputtext_parents_cannot_contain_clip'] = true;
+ quirks['inputtext_parents_cannot_contain_clip'] = true;
// flag for components (basefocusview for now) to minimize opacity
changes
- this.quirks['minimize_opacity_changes'] = true;
+ quirks['minimize_opacity_changes'] = true;
// multiline inputtext height must be set directly - height: 100%
does not work. See LPP-4119
- this.quirks['set_height_for_multiline_inputtext'] = true;
+ quirks['set_height_for_multiline_inputtext'] = true;
// text size measurement uses insertAdjacentHTML()
- this.quirks['text_measurement_use_insertadjacenthtml'] = true;
+ quirks['text_measurement_use_insertadjacenthtml'] = true;
+ quirks['text_selection_use_range'] = true;
} else if (Lz.__BrowserDetect.isSafari) {
// Fix bug in where if any parent of an image is hidden the size
is 0
// TODO: Tucker claims this is fixed in the latest version of
webkit
- this.quirks['invisible_parent_image_sizing_fix'] = true;
+ quirks['invisible_parent_image_sizing_fix'] = true;
// Remap alt/option key also sends control since control-click
shows context menu (see LPP-2584 - Lzpix: problem with multi-selecting images
in Safari 2.0.4, dhtml)
- this.quirks['alt_key_sends_control'] = true;
+ quirks['alt_key_sends_control'] = true;
// Safari scrollHeight needs to subtract scrollbar height
- this.quirks['safari_textarea_subtract_scrollbar_height'] = true;
+ quirks['safari_textarea_subtract_scrollbar_height'] = true;
// Safari doesn't like clipped or placed input text fields.
- this.quirks['safari_avoid_clip_position_input_text'] = true;
+ quirks['safari_avoid_clip_position_input_text'] = true;
// Safari won't show canvas tags whose parent is display: none
- this.quirks['safari_visibility_instead_of_display'] = true;
- this.quirks['absolute_position_accounts_for_offset'] = true;
- this.quirks['canvas_div_cannot_be_clipped'] = true;
+ quirks['safari_visibility_instead_of_display'] = true;
+ quirks['absolute_position_accounts_for_offset'] = true;
+ quirks['canvas_div_cannot_be_clipped'] = true;
if (Lz.__BrowserDetect.version > 523.10) {
this.capabilities['rotation'] = true;
}
} else if (Lz.__BrowserDetect.isOpera) {
// Fix bug in where if any parent of an image is hidden the size
is 0
- this.quirks['invisible_parent_image_sizing_fix'] = true;
- this.quirks['no_cursor_colresize'] = true;
- this.quirks['absolute_position_accounts_for_offset'] = true;
- this.quirks['canvas_div_cannot_be_clipped'] = true;
+ quirks['invisible_parent_image_sizing_fix'] = true;
+ quirks['no_cursor_colresize'] = true;
+ quirks['absolute_position_accounts_for_offset'] = true;
+ quirks['canvas_div_cannot_be_clipped'] = true;
} else if (Lz.__BrowserDetect.isFirefox && Lz.__BrowserDetect.version
< 2) {
// see
http://groups.google.ca/group/netscape.public.mozilla.dom/browse_thread/thread/821271ca11a1bdbf/46c87b49c026246f?lnk=st&q=+focus+nsIAutoCompletePopup+selectedIndex&rnum=1
- this.quirks['firefox_autocomplete_bug'] = true;
+ quirks['firefox_autocomplete_bug'] = true;
}
}
- if (this.quirks['safari_avoid_clip_position_input_text']) {
+ if (quirks['safari_avoid_clip_position_input_text']) {
LzSprite.prototype.__defaultStyles.lzswfinputtext.marginTop = '-2px';
LzSprite.prototype.__defaultStyles.lzswfinputtext.marginLeft = '-2px';
LzSprite.prototype.__defaultStyles.lzswfinputtextmultiline.marginTop =
'-2px';
LzSprite.prototype.__defaultStyles.lzswfinputtextmultiline.marginLeft
= '-2px';
}
- if (this.quirks['css_hide_canvas_during_init']) {
- if (this.quirks['safari_visibility_instead_of_display']) {
+ if (quirks['css_hide_canvas_during_init']) {
+ if (quirks['safari_visibility_instead_of_display']) {
LzSprite.prototype.__defaultStyles.lzcanvasdiv.visibility =
'hidden';
} else {
LzSprite.prototype.__defaultStyles.lzcanvasdiv.display = 'none';
@@ -333,7 +337,7 @@
LzSprite.prototype.__defaultStyles.lzcanvasclickdiv.display = 'none';
}
- if (this.quirks['hand_pointer_for_clickable']) {
+ if (quirks['hand_pointer_for_clickable']) {
LzSprite.prototype.__defaultStyles.lzclickdiv.cursor = 'pointer';
}
}
Modified: openlaszlo/trunk/test/lztest/lztest-text.lzx
===================================================================
--- openlaszlo/trunk/test/lztest/lztest-text.lzx 2007-12-19 22:55:04 UTC
(rev 7625)
+++ openlaszlo/trunk/test/lztest/lztest-text.lzx 2007-12-20 03:33:49 UTC
(rev 7626)
@@ -19,7 +19,8 @@
<text name="text3" resize="false" y="20" bgcolor="0xaaaaaa"/>
<!-- text4: simple text for checking selection methods -->
- <text name="text4" resize="false" bgcolor="0xaaaaaa"/>
+ <inputtext name="text4" resize="false" bgcolor="0xaaaaaa"/>
+ <inputtext name="text4ml" width="100" multiline="true" bgcolor="0xaaaaaa"/>
<!-- text5: simple text for checking scroll methods -->
<view name="view5">
@@ -287,6 +288,21 @@
LzTestManager.assertEquals (2, text4.getSelectionSize(),
"text4.getSelectionSize() failure (5)");
LzTestManager.assertEquals (0, text4.getSelectionPosition(),
"text4.getSelectionPosition() failure (5)");
+ if ($dhtml) {
+ text4ml.setText('\r\n01234\r\n\r\n567890123456789\r\n')
+ } else {
+ text4ml.setText('\n01234\n\n567890123456789\n')
+ }
+ text4ml.setSelection(5, 14);
+ LzTestManager.assertEquals (9, text4ml.getSelectionSize(),
"text4ml.getSelectionSize() failure (6)");
+ LzTestManager.assertEquals (5, text4ml.getSelectionPosition(),
"text4ml.getSelectionPosition() failure (6)");
+ text4ml.setSelection(6, 9);
+ LzTestManager.assertEquals (3, text4ml.getSelectionSize(),
"text4ml.getSelectionSize() failure (7)");
+ LzTestManager.assertEquals (6, text4ml.getSelectionPosition(),
"text4ml.getSelectionPosition() failure (7)");
+ text4ml.setSelection(5, 8);
+ LzTestManager.assertEquals (3, text4ml.getSelectionSize(),
"text4ml.getSelectionSize() failure (8)");
+ LzTestManager.assertEquals (5, text4ml.getSelectionPosition(),
"text4ml.getSelectionPosition() failure (8)");
+
/*
text4.setText (" "); // Note: The user cannot select a string of spaces
text4.setSelection (0, 4);
_______________________________________________
Laszlo-checkins mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-checkins