Author: bargull
Date: 2008-01-09 14:02:01 -0800 (Wed, 09 Jan 2008)
New Revision: 7793

Modified:
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
   openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js
   openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs
   openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs
Log:
Change 20080106-bargull-2 by [EMAIL PROTECTED] on 2008-01-06 17:19:46
    in /home/Admin/src/svn/openlaszlo/trunk
    for http://svn.openlaszlo.org/openlaszlo/trunk

Summary: Adding maxlength for multiline-inputtext (DHTML)

New Features:

Bugs Fixed: LPP-4747 - "Edittext maxlength does not work"

Technical Reviewer: max
QA Reviewer: promanik
Doc Reviewer: (pending)

Documentation:

Release Notes:

Details:
The HTML-<textarea> object does not support maxlength natively, so we need to 
implement a js-solution for DHTML.
To get the best visual experience, I'm using the "onkeypress"-event, this way 
we can easily interrupt any user-input as soon as the maxlength for the 
inputtext has been reached.
As keyboard-events are handled quite differently across all supported browsers, 
I needed to add a couple of new quirks to LzSprite, but most of them should be 
self-explanatory (also see http://www.quirksmode.org/js/keys.html).

Pasting text into an inputtext is special-handled to match Flash's behaviour as 
much as possible:
- for IE/Safari, I'm simply using the "onbeforepaste"-event
- for Firefox/Opera, I need to detect paste manually because these browsers do 
not support "onbeforepaste"
Flash-behaviour: you can only paste that much chars, as you have still 
available in the inputtext.

Changes in LzText and LzInputText fixes two "stale-data" bugs: you cannot use 
LzInputText#text to retrieve the current text-value, because this property does 
not get updated when the user types in any text. Instead of that, you must use 
LzInputText#getText().


Tests:
see bug-description



Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js  
2008-01-09 21:15:53 UTC (rev 7792)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzInputTextSprite.js  
2008-01-09 22:02:01 UTC (rev 7793)
@@ -1,7 +1,7 @@
 /**
   * LzInputTextSprite.js
   *
-  * @copyright Copyright 2007 Laszlo Systems, Inc.  All Rights Reserved.
+  * @copyright Copyright 2007-2008 Laszlo Systems, Inc.  All Rights Reserved.
   *            Use is subject to license terms.
   *
   * @topic Kernel
@@ -34,6 +34,7 @@
 // Should reflect CSS defaults in LzSprite.js
 LzInputTextSprite.prototype.____hpadding = 2;
 LzInputTextSprite.prototype.____wpadding = 2;
+LzInputTextSprite.prototype.____crregexp = new RegExp('\\r\\n', 'g');
 
 LzInputTextSprite.prototype.__createInputText = function(t) {
     if (this.__LzInputDiv) return;
@@ -216,8 +217,12 @@
         this.__LzInputDiv.onclick = function (e) { this.owner.__textEvent(e, 
'onclick') }
         this.__LzInputDiv.onkeyup = function (e) { this.owner.__textEvent(e, 
'onkeyup') }
         this.__LzInputDiv.onkeydown = function (e) { this.owner.__textEvent(e, 
'onkeydown') }
+        this.__LzInputDiv.onkeypress = function (e) { 
this.owner.__textEvent(e, 'onkeypress') }
         this.__LzInputDiv.onselect = function (e) { this.owner.__textEvent(e, 
'onselect') }
         this.__LzInputDiv.onchange = function (e) { this.owner.__textEvent(e, 
'onchange') }
+        if (this.quirks.ie_paste_event || this.quirks.safari_paste_event) {
+            this.__LzInputDiv.onpaste = function (e) { 
this.owner.__pasteHandlerEx(e) }
+        }
     } else {
         this.__LzInputDiv.onblur = null;
         this.__LzInputDiv.onmousedown = null;
@@ -225,11 +230,108 @@
         this.__LzInputDiv.onclick = null;
         this.__LzInputDiv.onkeyup = null;
         this.__LzInputDiv.onkeydown = null;
+        this.__LzInputDiv.onkeypress = null;
         this.__LzInputDiv.onselect = null;
         this.__LzInputDiv.onchange = null;
+        if (this.quirks.ie_paste_event || this.quirks.safari_paste_event) {
+            this.__LzInputDiv.onpaste = null;
+        }
     }
 }
 
+LzInputTextSprite.prototype.__pasteHandlerEx = function (evt) {
+    if (this.multiline && this.owner.maxlength > 0) {
+        evt = evt ? evt : window.event;
+        
+        if (this.quirks.safari_paste_event) {
+            var clipboardTxt = evt.clipboardData.getData("text/plain");
+        } else {
+            var clipboardTxt = window.clipboardData.getData("TEXT");
+            clipboardTxt = clipboardTxt.replace(this.____crregexp, '\n');
+        }
+        
+        if (this.quirks.text_ie_carriagereturn) {
+            var len = this.__LzInputDiv.value.replace(this.____crregexp, 
'\n').length;
+        } else {
+            var len = this.__LzInputDiv.value.length;
+        }
+        
+        var selsize = this.getSelectionSize();
+        if (selsize < 0) selsize = 0;//[TODO anba 2008-01-06] remove after 
LPP-5330
+        var max = this.owner.maxlength + selsize;
+        var stopPaste = false;
+        
+        var maxchars = max - len;
+        if (maxchars > 0) {
+            var txt = clipboardTxt;
+            var txtLen = txt.length;
+            
+            if (txtLen > maxchars) {
+                txt = txt.substring(0, maxchars);
+                stopPaste = true;
+            }
+        } else {
+            var txt = "";
+            stopPaste = true;
+        }
+        
+        if (stopPaste) {
+            evt.returnValue = false;
+            if (evt.preventDefault) {
+                evt.preventDefault();
+            }
+            
+            if (txt.length > 0) {
+                if (this.quirks.safari_paste_event) {
+                    var val = this.__LzInputDiv.value;
+                    var selpos = this.getSelectionPosition();
+                    
+                    //update value
+                    this.__LzInputDiv.value = val.substring(0, selpos) + txt + 
val.substring(selpos + selsize);
+                    
+                    //fix selection
+                    this.__LzInputDiv.setSelectionRange(selpos + txt.length, 
selpos + txt.length);
+                } else {
+                    var range = document.selection.createRange();
+                    //this updates value and ensures right selection
+                    range.text = txt;
+                }
+            }
+        }
+    }
+}
+
+LzInputTextSprite.prototype.__pasteHandler = function () {
+    var selpos = this.getSelectionPosition();
+    var selsize = this.getSelectionSize();
+    var val = this.__LzInputDiv.value;
+    var that = this;
+    
+    //use 1ms timeout to give UI enough time for updating
+    setTimeout(function() {
+        var newval = that.__LzInputDiv.value;
+        var newlen = newval.length;
+        var max = that.owner.maxlength;
+        
+        if (newlen > max) {
+            var len = val.length;
+            var maxchars = max + selsize - len;
+            
+            //this was pasted
+            var newc = newval.substr(selpos, newlen - len + selsize);
+            //but we can only take at max that many chars
+            newc = newc.substring(0, maxchars);
+            
+            //update value
+            that.__LzInputDiv.value = val.substring(0, selpos) + newc + 
val.substring(selpos + selsize);
+            
+            //fix selection
+            //note: we're in Firefox/Opera, so we can savely call 
"setSelectionRange"
+            that.__LzInputDiv.setSelectionRange(selpos + newc.length, selpos + 
newc.length);
+        }
+    }, 1);
+}
+
 LzInputTextSprite.prototype.__textEvent = function ( e, eventname ){
     if (this.__LZdeleted == true) return;
     var keycode = e ? e.keyCode : event.keyCode;
@@ -258,6 +360,70 @@
         this.__setglobalclickable(true);
     }
 
+    if (this.multiline && this.owner.maxlength > 0) {
+        if (eventname == 'onkeypress') {
+            var evt = e ? e : event;
+            var charcode = this.quirks.text_event_charcode ? evt.charCode : 
evt.keyCode;
+            
+            /* BUG:
+             * env: Safari - Win
+             * -> last char is \n, delete per backspace, notice Safari-UI did 
update, 
+             *      but __LzInputDiv.value still holds the \n!
+             *    blur inputtext, focus again -> \n is again there, also in UI!
+             * what about Safari - Mac?
+             */
+            
+            //Debug.write("charCode = %s, keyCode = %s, ctrlKey = %s, altKey = 
%s, shiftKey = %s", charcode, keycode, evt.ctrlKey, evt.altKey, evt.shiftKey);
+            
+            if (!(evt.ctrlKey || evt.altKey) && (charcode || keycode == 13) && 
keycode != 8) {
+                var selsize = this.getSelectionSize();
+                //[TODO anba 2008-01-06] use selsize==0 when LPP-5330 is fixed
+                if (selsize <= 0) {
+                    if (this.quirks.text_ie_carriagereturn) {
+                        var val = 
this.__LzInputDiv.value.replace(this.____crregexp, '\n');
+                    } else {
+                        var val = this.__LzInputDiv.value;
+                    }
+                    
+                    var len = val.length, max = this.owner.maxlength;
+                    if (len >= max) {
+                        evt.returnValue = false;
+                        if (evt.preventDefault) {
+                            evt.preventDefault();
+                        }
+                    }
+                }
+            } else {
+                /* IE and Safari do not send 'onkeypress' for function-keys, */
+                /* but Firefox and Opera! */
+                if (this.quirks.keypress_function_keys) {
+                    if (evt.ctrlKey && !evt.altKey && !evt.shiftKey) {
+                        var c = String.fromCharCode(charcode);
+                        /* 'v' for Firefox and 'V' for Opera */
+                        if (c == 'v' || c == 'V') {
+                            //pasting per ctrl + v
+                            //[TODO anba 2008-01-06] how to detect paste per 
context-menu?
+                            var len = this.__LzInputDiv.value.length, max = 
this.owner.maxlength;
+                            if (len < max || this.getSelectionSize() > 0) {
+                                this.__pasteHandler();
+                            } else {
+                                evt.returnValue = false;
+                                if (evt.preventDefault) {
+                                    evt.preventDefault();
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    
+    if (eventname == 'onkeypress') {
+        /* we need to leave here, else LzInputText.inputtextevent(..) will 
freak out */
+        return;
+    }
+
     //Debug.info('__textEvent', eventname, keycode);
     if (this.owner) {
         // Generate the event. onkeyup/onkeydown sent by LzKeys.js
@@ -623,7 +789,11 @@
 }
 
 LzInputTextSprite.prototype.getText = function () {
-    return this.__LzInputDiv.value;
+    if (this.multiline && this.quirks.text_ie_carriagereturn) {
+        return this.__LzInputDiv.value.replace(this.____crregexp, '\n');
+    } else {
+        return this.__LzInputDiv.value;
+    }
 }
 
 LzInputTextSprite.prototype.getTextfieldHeight = function () {

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js   2008-01-09 
21:15:53 UTC (rev 7792)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/kernel/dhtml/LzSprite.js   2008-01-09 
22:02:01 UTC (rev 7793)
@@ -229,6 +229,11 @@
     ,text_measurement_use_insertadjacenthtml: false
     ,text_selection_use_range: false
     ,document_size_use_offsetheight: false
+    ,text_ie_carriagereturn: false
+    ,ie_paste_event: false
+    ,safari_paste_event: false
+    ,text_event_charcode: true
+    ,keypress_function_keys: true
 }
 
 LzSprite.prototype.capabilities = {
@@ -292,6 +297,16 @@
             // text size measurement uses insertAdjacentHTML()
             quirks['text_measurement_use_insertadjacenthtml'] = true;
             quirks['text_selection_use_range'] = true;
+            
+            // IE uses "\r\n" for newlines, which gives different text-lengths 
compared to SWF and
+            // to other browsers
+            quirks['text_ie_carriagereturn'] = true;
+            // IE has got a special event for pasting
+            quirks['ie_paste_event'] = true;
+            // IE does not send onkeypress for function keys
+            quirks['keypress_function_keys'] = false;
+            // IE does not use charCode for onkeypress
+            quirks['text_event_charcode'] = false;
         } 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
@@ -313,6 +328,11 @@
             if (Lz.__BrowserDetect.version > 523.10) {
                 this.capabilities['rotation'] = true;
             }
+            
+            // Safari has got a special event for pasting
+            quirks['safari_paste_event'] = true;
+            // Safari does not send onkeypress for function keys
+            quirks['keypress_function_keys'] = false;
         } else if (Lz.__BrowserDetect.isOpera) {
             // Fix bug in where if any parent of an image is hidden the size 
is 0
             quirks['invisible_parent_image_sizing_fix'] = true;
@@ -320,6 +340,8 @@
             quirks['absolute_position_accounts_for_offset'] = true;
             quirks['canvas_div_cannot_be_clipped'] = true;
             quirks['document_size_use_offsetheight'] = true;
+            // Opera does not use charCode for onkeypress
+            quirks['text_event_charcode'] = false;
         } 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
             quirks['firefox_autocomplete_bug'] = true;

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs      2008-01-09 
21:15:53 UTC (rev 7792)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/views/LzInputText.lzs      2008-01-09 
22:02:01 UTC (rev 7793)
@@ -1,6 +1,6 @@
 /**
   *
-  * @copyright Copyright 2001-2007 Laszlo Systems, Inc.  All Rights Reserved.
+  * @copyright Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.
   *            Use is subject to license terms.
   *
   * @access public
@@ -171,7 +171,7 @@
   * @access protected
   */
 function updateData (){
-    return this.sprite.text;
+    return this.sprite.getText();
 }
 
 

Modified: openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs
===================================================================
--- openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs   2008-01-09 21:15:53 UTC 
(rev 7792)
+++ openlaszlo/trunk/WEB-INF/lps/lfc/views/LzText.lzs   2008-01-09 22:02:01 UTC 
(rev 7793)
@@ -1,6 +1,6 @@
 /**
   *
-  * @copyright Copyright 2001-2007 Laszlo Systems, Inc.  All Rights Reserved.
+  * @copyright Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.
   *            Use is subject to license terms.
   *
   * @access public
@@ -459,8 +459,9 @@
     this.maxlength = val;
     if (this.onmaxlength.ready) this.onmaxlength.sendEvent(val);
 
-    if(this.text && this.text.length > this.maxlength){
-        this.setText (this.text, true);
+    var t = this.getText();
+    if(t && t.length > this.maxlength){
+        this.setText (t, true);
     }
 }
 


_______________________________________________
Laszlo-checkins mailing list
[email protected]
http://www.openlaszlo.org/mailman/listinfo/laszlo-checkins

Reply via email to