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