1 /****************************************************************************
  2  Copyright (c) 2010-2012 cocos2d-x.org
  3 
  4  http://www.cocos2d-x.org
  5 
  6  Permission is hereby granted, free of charge, to any person obtaining a copy
  7  of this software and associated documentation files (the "Software"), to deal
  8  in the Software without restriction, including without limitation the rights
  9  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  copies of the Software, and to permit persons to whom the Software is
 11  furnished to do so, subject to the following conditions:
 12 
 13  The above copyright notice and this permission notice shall be included in
 14  all copies or substantial portions of the Software.
 15 
 16  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22  THE SOFTWARE.
 23  ****************************************************************************/
 24 ccs.TextFiledEventType = {
 25     attach_with_me: 0,
 26     detach_with_ime: 1,
 27     insert_text: 2,
 28     delete_backward: 3
 29 };
 30 
 31 /**
 32  * Base class for ccs.UICCTextField
 33  * @class
 34  * @extends cc.TextFieldTTF
 35  */
 36 ccs.UICCTextField = cc.TextFieldTTF.extend({
 37     _maxLengthEnabled: false,
 38     _maxLength: 0,
 39     _passwordEnabled: false,
 40     _passwordStyleText: "",
 41     _attachWithIME: false,
 42     _detachWithIME: false,
 43     _insertText: false,
 44     _deleteBackward: false,
 45     ctor: function () {
 46         cc.TextFieldTTF.prototype.ctor.call(this);
 47         this._maxLengthEnabled = false;
 48         this._maxLength = 0;
 49         this._passwordEnabled = false;
 50         this._passwordStyleText = "*";
 51         this._attachWithIME = false;
 52         this._detachWithIME = false;
 53         this._insertText = false;
 54         this._deleteBackward = false;
 55     },
 56     onEnter: function () {
 57         cc.TextFieldTTF.prototype.onEnter.call(this);
 58         cc.TextFieldTTF.prototype.setDelegate.call(this,this);
 59     },
 60 
 61     //CCTextFieldDelegate
 62 
 63     onTextFieldAttachWithIME: function (sender) {
 64         this.setAttachWithIME(true);
 65         return false;
 66     },
 67 
 68     onTextFieldInsertText: function (sender, text, len) {
 69         if (len == 1 && text == "\n") {
 70             return false;
 71         }
 72         this.setInsertText(true);
 73         if (this._maxLengthEnabled) {
 74             if (cc.TextFieldTTF.prototype.getCharCount.call(this) >= this._maxLength) {
 75                 return true;
 76             }
 77         }
 78 
 79         return false;
 80     },
 81 
 82     onTextFieldDeleteBackward: function (sender, delText, nLen) {
 83         this.setDeleteBackward(true);
 84         return false;
 85     },
 86 
 87     onTextFieldDetachWithIME: function (sender) {
 88         this.setDetachWithIME(true);
 89         return false;
 90     },
 91 
 92     insertText: function (text, len) {
 93         var str_text = text;
 94         var locString = cc.TextFieldTTF.prototype.getString.call(this);
 95         var str_len = locString.length;
 96         var multiple, header;
 97         if (text != "\n") {
 98             if (this._maxLengthEnabled) {
 99                 multiple = 1;
100                 header = text.charCodeAt(0);
101                 if (header < 0 || header > 127) {
102                     multiple = 3;
103                 }
104 
105                 if (str_len + len > this._maxLength * multiple) {
106                     str_text = str_text.substr(0, this._maxLength * multiple);
107                     len = this._maxLength * multiple;
108                 }
109             }
110         }
111         cc.TextFieldTTF.prototype.insertText.call(this,str_text, len);
112 
113         // password
114         if (this._passwordEnabled) {
115             if (cc.TextFieldTTF.prototype.getCharCount.call(this) > 0) {
116                 this.setPasswordText(this._inputText);
117             }
118         }
119     },
120 
121     deleteBackward: function () {
122         cc.TextFieldTTF.prototype.deleteBackward.call(this);
123 
124         if (cc.TextFieldTTF.prototype.getCharCount.call(this) > 0) {
125             // password
126             if (this._passwordEnabled) {
127                 this.setPasswordText(this._inputText);
128             }
129         }
130     },
131 
132     openIME: function () {
133         cc.TextFieldTTF.prototype.attachWithIME.call(this);
134     },
135 
136     closeIME: function () {
137         cc.TextFieldTTF.prototype.detachWithIME.call(this);
138     },
139     onDraw:function (sender) {
140         return false;
141     },
142     setMaxLengthEnabled: function (enable) {
143         this._maxLengthEnabled = enable;
144     },
145 
146     isMaxLengthEnabled: function () {
147         return this._maxLengthEnabled;
148     },
149 
150     setMaxLength: function (length) {
151         this._maxLength = length;
152     },
153 
154     getMaxLength: function () {
155         return this._maxLength;
156     },
157 
158     getCharCount: function () {
159         return cc.TextFieldTTF.prototype.getCharCount.call(this);
160     },
161 
162     setPasswordEnabled: function (enable) {
163         this._passwordEnabled = enable;
164     },
165 
166     isPasswordEnabled: function () {
167         return this._passwordEnabled;
168     },
169 
170     setPasswordStyleText: function (styleText) {
171         if (styleText.length > 1) {
172             return;
173         }
174         var header = styleText.charCodeAt(0);
175         if (header < 33 || header > 126) {
176             return;
177         }
178         this._passwordStyleText = styleText;
179     },
180 
181     setPasswordText: function (text) {
182         var tempStr = "";
183         for (var i = 0; i < text.length; ++i) {
184             tempStr += this._passwordStyleText;
185         }
186         cc.LabelTTF.prototype.setString.call(this, tempStr);
187     },
188 
189     setAttachWithIME: function (attach) {
190         this._attachWithIME = attach;
191     },
192 
193     getAttachWithIME: function () {
194         return this._attachWithIME;
195     },
196 
197     setDetachWithIME: function (detach) {
198         this._detachWithIME = detach;
199     },
200 
201     getDetachWithIME: function () {
202         return this._detachWithIME;
203     },
204 
205     setInsertText: function (insert) {
206         this._insertText = insert;
207     },
208 
209     getInsertText: function () {
210         return this._insertText;
211     },
212 
213     setDeleteBackward: function (deleteBackward) {
214         this._deleteBackward = deleteBackward;
215     },
216 
217     getDeleteBackward: function () {
218         return this._deleteBackward;
219     }
220 });
221 
222 ccs.UICCTextField.create = function (placeholder, fontName, fontSize) {
223     var ret = new ccs.UICCTextField();
224     if (ret && ret.initWithString("", fontName, fontSize)) {
225         if (placeholder) {
226             ret.setPlaceHolder(placeholder);
227         }
228         return ret;
229     }
230     return null;
231 };
232 
233 /**
234  * Base class for ccs.UITextField
235  * @class
236  * @extends ccs.UIWidget
237  */
238 ccs.UITextField = ccs.UIWidget.extend(/** @lends ccs.UITextField# */{
239     _textFieldRender: null,
240     _touchWidth: 0,
241     _touchHeight: 0,
242     _useTouchArea: false,
243     _textFieldEventListener: null,
244     _textFieldEventSelector: null,
245     _attachWithIMEListener: null,
246     _detachWithIMEListener: null,
247     _insertTextListener: null,
248     _deleteBackwardListener: null,
249     _attachWithIMESelector: null,
250     _detachWithIMESelector: null,
251     _insertTextSelector: null,
252     _deleteBackwardSelector: null,
253     _passwordStyleText:"",
254     ctor: function () {
255         ccs.UIWidget.prototype.ctor.call(this);
256         this._textFieldRender = null;
257         this._touchWidth = 0;
258         this._touchHeight = 0;
259         this._useTouchArea = false;
260 
261         this._textFieldEventListener = null;
262         this._textFieldEventSelector = null;
263         this._attachWithIMEListener = null;
264         this._detachWithIMEListener = null;
265         this._insertTextListener = null;
266         this._deleteBackwardListener = null;
267         this._attachWithIMESelector = null;
268         this._detachWithIMESelector = null;
269         this._insertTextSelector = null;
270         this._deleteBackwardSelector = null;
271     },
272 
273     init: function () {
274         if (ccs.UIWidget.prototype.init.call(this)) {
275             this.setUpdateEnabled(true);
276             return true;
277         }
278         return false;
279     },
280 
281     initRenderer: function () {
282         ccs.UIWidget.prototype.initRenderer.call(this);
283         this._textFieldRender = ccs.UICCTextField.create("input words here", "Thonburi", 20);
284         this._renderer.addChild(this._textFieldRender);
285 
286     },
287 
288     /**
289      * set touch size
290      * @param {cc.Size} size
291      */
292     setTouchSize: function (size) {
293         this._useTouchArea = true;
294         this._touchWidth = size.width;
295         this._touchHeight = size.height;
296     },
297 
298     /**
299      *  Changes the string value of textField.
300      * @param {String} text
301      */
302     setText: function (text) {
303         if (!text) {
304             return;
305         }
306         this._textFieldRender.setString(text);
307         this.textfieldRendererScaleChangedWithSize();
308     },
309 
310     /**
311      * @param {String} value
312      */
313     setPlaceHolder: function (value) {
314         this._textFieldRender.setPlaceHolder(value);
315         this.textfieldRendererScaleChangedWithSize();
316     },
317 
318     /**
319      * @param {cc.Size} size
320      */
321     setFontSize: function (size) {
322         this._textFieldRender.setFontSize(size);
323         this.textfieldRendererScaleChangedWithSize();
324     },
325 
326     /**
327      * @param {String} name
328      */
329     setFontName: function (name) {
330         this._textFieldRender.setFontName(name);
331         this.textfieldRendererScaleChangedWithSize();
332     },
333 
334     /**
335      * detach with IME
336      */
337     didNotSelectSelf: function () {
338         this._textFieldRender.detachWithIME();
339     },
340 
341     /**
342      * get textField string value
343      * @returns {String}
344      */
345     getStringValue: function () {
346         return this._textFieldRender.getString();
347     },
348 
349     /**
350      * touch began
351      * @param {cc.Point} touchPoint
352      */
353     onTouchBegan: function (touchPoint) {
354         var pass = ccs.UIWidget.prototype.onTouchBegan.call(this, touchPoint);
355         return pass;
356     },
357 
358     /**
359      * touch ended
360      * @param touchPoint
361      */
362     onTouchEnded: function (touchPoint) {
363         ccs.UIWidget.prototype.onTouchEnded.call(this, touchPoint);
364         this._textFieldRender.attachWithIME();
365     },
366 
367     /**
368      * @param {Boolean} enable
369      */
370     setMaxLengthEnabled: function (enable) {
371         this._textFieldRender.setMaxLengthEnabled(enable);
372     },
373 
374     /**
375      * @returns {Boolean}
376      */
377     isMaxLengthEnabled: function () {
378         return this._textFieldRender.isMaxLengthEnabled();
379     },
380 
381     /**
382      * @param {number} length
383      */
384     setMaxLength: function (length) {
385         this._textFieldRender.setMaxLength(length);
386     },
387 
388     /**
389      * @returns {number} length
390      */
391     getMaxLength: function () {
392         return this._textFieldRender.getMaxLength();
393     },
394 
395     /**
396      * @param {Boolean} enable
397      */
398     setPasswordEnabled: function (enable) {
399         this._textFieldRender.setPasswordEnabled(enable);
400     },
401 
402     /**
403      * @returns {Boolean}
404      */
405     isPasswordEnabled: function () {
406         return this._textFieldRender.isPasswordEnabled();
407     },
408 
409     /**
410      * @param {String} enable
411      */
412     setPasswordStyleText: function (styleText) {
413         this._textFieldRender.setPasswordStyleText(styleText);
414         this._passwordStyleText = styleText;
415     },
416 
417     update: function (dt) {
418         if (this.getAttachWithIME()) {
419             this.attachWithIMEEvent();
420             this.setAttachWithIME(false);
421         }
422         if (this.getDetachWithIME()) {
423             this.detachWithIMEEvent();
424             this.setDetachWithIME(false);
425         }
426         if (this.getInsertText()) {
427             this.insertTextEvent();
428             this.setInsertText(false);
429 
430             this.textfieldRendererScaleChangedWithSize();
431         }
432         if (this.getDeleteBackward()) {
433             this.deleteBackwardEvent();
434             this.setDeleteBackward(false);
435         }
436     },
437 
438     /**
439      * get whether attach with IME.
440      * @returns {Boolean}
441      */
442     getAttachWithIME: function () {
443         return this._textFieldRender.getAttachWithIME();
444     },
445 
446     /**
447      * set attach with IME.
448      * @param {Boolean} attach
449      */
450     setAttachWithIME: function (attach) {
451         this._textFieldRender.setAttachWithIME(attach);
452     },
453 
454     /**
455      * get whether eetach with IME.
456      * @returns {Boolean}
457      */
458     getDetachWithIME: function () {
459         return this._textFieldRender.getDetachWithIME();
460     },
461 
462     /**
463      * set detach with IME.
464      * @param {Boolean} detach
465      */
466     setDetachWithIME: function (detach) {
467         this._textFieldRender.setDetachWithIME(detach);
468     },
469 
470     /**
471      * get insertText
472      * @returns {String}
473      */
474     getInsertText: function () {
475         return this._textFieldRender.getInsertText();
476     },
477 
478     /**
479      * set insertText
480      * @param {String} insertText
481      */
482     setInsertText: function (insertText) {
483         this._textFieldRender.setInsertText(insertText);
484     },
485 
486     /**
487      * @returns {Boolean}
488      */
489     getDeleteBackward: function () {
490         return this._textFieldRender.getDeleteBackward();
491     },
492 
493     /**
494      * @param {Boolean} deleteBackward
495      */
496     setDeleteBackward: function (deleteBackward) {
497         this._textFieldRender.setDeleteBackward(deleteBackward);
498     },
499 
500     attachWithIMEEvent: function () {
501         if (this._textFieldEventListener && this._textFieldEventSelector) {
502             this._textFieldEventSelector.call(this._textFieldEventListener, this, ccs.TextFiledEventType.attach_with_me);
503         }
504     },
505 
506     detachWithIMEEvent: function () {
507         if (this._textFieldEventListener && this._textFieldEventSelector) {
508             this._textFieldEventSelector.call(this._textFieldEventListener, this, ccs.TextFiledEventType.detach_with_ime);
509         }
510     },
511 
512     insertTextEvent: function () {
513         if (this._textFieldEventListener && this._textFieldEventSelector) {
514             this._textFieldEventSelector.call(this._textFieldEventListener, this, ccs.TextFiledEventType.insert_text);
515         }
516     },
517 
518     deleteBackwardEvent: function () {
519         if (this._textFieldEventListener && this._textFieldEventSelector) {
520             this._textFieldEventSelector.call(this._textFieldEventListener, this, ccs.TextFiledEventType.delete_backward);
521         }
522     },
523 
524     /**
525      * add event listener
526      * @param {Function} selector
527      * @param {Object} target
528      */
529     addEventListenerTextField: function (selector, target) {
530         this._textFieldEventSelector = selector;
531         this._textFieldEventListener = target;
532     },
533 
534     /**
535      * check hit
536      * @param {cc.Point} pt
537      * @returns {boolean}
538      */
539     hitTest: function (pt) {
540         var nsp = this._renderer.convertToNodeSpace(pt);
541         var locSize = this._textFieldRender.getContentSize();
542         var bb = cc.rect(-locSize.width * this._anchorPoint.x, -locSize.height * this._anchorPoint.y, locSize.width, locSize.height);
543         if (nsp.x >= bb.x && nsp.x <= bb.x + bb.width && nsp.y >= bb.y && nsp.y <= bb.y + bb.height) {
544             return true;
545         }
546         return false;
547     },
548 
549     /**
550      * override "setAnchorPoint" of widget.
551      * @param {cc.Point} pt
552      */
553     setAnchorPoint: function (pt) {
554         ccs.UIWidget.prototype.setAnchorPoint.call(this, pt);
555         this._textFieldRender.setAnchorPoint(pt);
556     },
557 
558     /**
559      * @param {cc.c3b} color
560      */
561     setColor: function (color) {
562         ccs.UIWidget.prototype.setColor.call(this, color);
563         this._textFieldRender.setColor(color);
564     },
565 
566     /**
567      * @param {number} opacity
568      */
569     setOpacity: function (opacity) {
570         ccs.UIWidget.prototype.setOpacity.call(this, opacity);
571         this._textFieldRender.setOpacity(opacity);
572     },
573 
574     onSizeChanged: function () {
575         this.textfieldRendererScaleChangedWithSize();
576     },
577 
578     textfieldRendererScaleChangedWithSize: function () {
579         if (this._ignoreSize) {
580             this._textFieldRender.setScale(1.0);
581             this._size = this.getContentSize();
582         }
583         else {
584             var textureSize = this.getContentSize();
585             if (textureSize.width <= 0.0 || textureSize.height <= 0.0) {
586                 this._textFieldRender.setScale(1.0);
587                 return;
588             }
589             var scaleX = this._size.width / textureSize.width;
590             var scaleY = this._size.height / textureSize.height;
591             this._textFieldRender.setScaleX(scaleX);
592             this._textFieldRender.setScaleY(scaleY);
593         }
594     },
595 
596     /**
597      * override "getContentSize" method of widget.
598      * @returns {cc.Size}
599      */
600     getContentSize: function () {
601         return this._textFieldRender.getContentSize();
602     },
603 
604     /**
605      * override "getContentSize" method of widget.
606      * @returns {cc.Node}
607      */
608     getVirtualRenderer: function () {
609         return this._textFieldRender;
610     },
611 
612     /**
613      * Returns the "class name" of widget.
614      * @returns {string}
615      */
616     getDescription: function () {
617         return "TextField";
618     },
619 
620     attachWithIME: function () {
621         this._textFieldRender.attachWithIME();
622     },
623 
624     createCloneInstance: function () {
625         return ccs.UITextField.create();
626     },
627 
628     copySpecialProperties: function (textField) {
629         this.setText(textField._textFieldRender.getString());
630         this.setPlaceHolder(textField.getStringValue());
631         this.setFontSize(textField._textFieldRender.getFontSize());
632         this.setFontName(textField._textFieldRender.getFontName());
633         this.setMaxLengthEnabled(textField.isMaxLengthEnabled());
634         this.setMaxLength(textField.getMaxLength());
635         this.setPasswordEnabled(textField.isPasswordEnabled());
636         this.setPasswordStyleText(textField._passwordStyleText);
637         this.setAttachWithIME(textField.getAttachWithIME());
638         this.setDetachWithIME(textField.getDetachWithIME());
639         this.setInsertText(textField.getInsertText());
640         this.setDeleteBackward(textField.getDeleteBackward());
641     }
642 });
643 /**
644  * allocates and initializes a UITextField.
645  * @constructs
646  * @return {ccs.UITextField}
647  * @example
648  * // example
649  * var uiTextField = ccs.UITextField.create();
650  */
651 ccs.UITextField.create = function () {
652     var uiTextField = new ccs.UITextField();
653     if (uiTextField && uiTextField.init()) {
654         return uiTextField;
655     }
656     return null;
657 };