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 &apos; 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

Reply via email to