1 /****************************************************************************
  2  Copyright (c) 2008-2010 Ricardo Quesada
  3  Copyright (c) 2011-2012 cocos2d-x.org
  4  Copyright (c) 2013-2014 Chukong Technologies Inc.
  5 
  6  http://www.cocos2d-x.org
  7 
  8  Permission is hereby granted, free of charge, to any person obtaining a copy
  9  of this software and associated documentation files (the "Software"), to deal
 10  in the Software without restriction, including without limitation the rights
 11  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12  copies of the Software, and to permit persons to whom the Software is
 13  furnished to do so, subject to the following conditions:
 14 
 15  The above copyright notice and this permission notice shall be included in
 16  all copies or substantial portions of the Software.
 17 
 18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24  THE SOFTWARE.
 25  ****************************************************************************/
 26 
 27 /**
 28  * Text field delegate
 29  * @class
 30  * @extends cc.Class
 31  */
 32 cc.TextFieldDelegate = cc.Class.extend(/** @lends cc.TextFieldDelegate# */{
 33     /**
 34      * If the sender doesn't want to attach with IME, return true;
 35      * @param {cc.TextFieldTTF} sender
 36      * @return {Boolean}
 37      */
 38     onTextFieldAttachWithIME:function (sender) {
 39         return false;
 40     },
 41 
 42     /**
 43      * If the sender doesn't want to detach with IME, return true;
 44      * @param {cc.TextFieldTTF} sender
 45      * @return {Boolean}
 46      */
 47     onTextFieldDetachWithIME:function (sender) {
 48         return false;
 49     },
 50 
 51     /**
 52      * If the sender doesn't want to insert the text, return true;
 53      * @param {cc.TextFieldTTF} sender
 54      * @param {String} text
 55      * @param {Number} len
 56      * @return {Boolean}
 57      */
 58     onTextFieldInsertText:function (sender, text, len) {
 59         return false
 60     },
 61 
 62     /**
 63      * If the sender doesn't want to delete the delText, return true;
 64      * @param {cc.TextFieldTTF} sender
 65      * @param {String} delText
 66      * @param {Number} len
 67      * @return {Boolean}
 68      */
 69     onTextFieldDeleteBackward:function (sender, delText, len) {
 70         return false;
 71     },
 72 
 73     /**
 74      * If doesn't want draw sender as default, return true.
 75      * @param {cc.TextFieldTTF} sender
 76      * @return {Boolean}
 77      */
 78     onDraw:function (sender) {
 79         return false;
 80     }
 81 });
 82 
 83 /**
 84  * A simple text input field with TTF font.
 85  * @class
 86  * @extends cc.LabelTTF
 87  *
 88  * @property {cc.Node}      delegate            - Delegate
 89  * @property {Number}       charCount           - <@readonly> Characators count
 90  * @property {String}       placeHolder         - Place holder for the field
 91  * @property {cc.Color}     colorSpaceHolder
 92  *
 93  * @param {String} placeholder
 94  * @param {cc.Size} dimensions
 95  * @param {Number} alignment
 96  * @param {String} fontName
 97  * @param {Number} fontSize
 98  *
 99  * @example
100  * //example
101  * // When five parameters
102  * var textField = new cc.TextFieldTTF("<click here for input>", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32);
103  * // When three parameters
104  * var textField = new cc.TextFieldTTF("<click here for input>", "Arial", 32);
105  */
106 cc.TextFieldTTF = cc.LabelTTF.extend(/** @lends cc.TextFieldTTF# */{
107 	delegate:null,
108 	colorSpaceHolder:null,
109 
110     _colorText: null,
111     _lens:null,
112     _inputText:"",
113     _placeHolder:"",
114     _charCount:0,
115     _className:"TextFieldTTF",
116 
117     /**
118      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. <br />
119      * creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size.
120      * @param {String} placeholder
121      * @param {cc.Size} dimensions
122      * @param {Number} alignment
123      * @param {String} fontName
124      * @param {Number} fontSize
125      */
126     ctor:function (placeholder, dimensions, alignment, fontName, fontSize) {
127         this.colorSpaceHolder = cc.color(127, 127, 127);
128         this._colorText = cc.color(255,255,255, 255);
129         cc.imeDispatcher.addDelegate(this);
130         cc.LabelTTF.prototype.ctor.call(this);
131 
132         if(fontSize !== undefined){
133             this.initWithPlaceHolder("", dimensions, alignment, fontName, fontSize);
134             if(placeholder)
135                 this.setPlaceHolder(placeholder);
136         }else if(fontName === undefined && alignment !== undefined){
137             this.initWithString("", arguments[1], arguments[2]);
138             if(placeholder)
139                 this.setPlaceHolder(placeholder);
140         }
141     },
142 
143     /**
144      * Gets the delegate.
145      * @return {cc.Node}
146      */
147     getDelegate:function () {
148         return this.delegate;
149     },
150 
151     /**
152      * Set the delegate.
153      * @param {cc.Node} value
154      */
155     setDelegate:function (value) {
156         this.delegate = value;
157     },
158 
159     /**
160      * Gets the char count.
161      * @return {Number}
162      */
163     getCharCount:function () {
164         return this._charCount;
165     },
166 
167     /**
168      * Returns the color of space holder.
169      * @return {cc.Color}
170      */
171     getColorSpaceHolder:function () {
172         return cc.color(this.colorSpaceHolder);
173     },
174 
175     /**
176      * Sets the color of space holder.
177      * @param {cc.Color} value
178      */
179     setColorSpaceHolder:function (value) {
180         this.colorSpaceHolder.r = value.r;
181         this.colorSpaceHolder.g = value.g;
182         this.colorSpaceHolder.b = value.b;
183         this.colorSpaceHolder.a = cc.isUndefined(value.a) ? 255 : value.a;
184     },
185 
186     /**
187      * Sets the color of cc.TextFieldTTF's text.
188      * @param {cc.Color} textColor
189      */
190     setTextColor:function(textColor){
191         this._colorText.r = textColor.r;
192         this._colorText.g = textColor.g;
193         this._colorText.b = textColor.b;
194         this._colorText.a = cc.isUndefined(textColor.a) ? 255 : textColor.a;
195     },
196 
197     /**
198      * Initializes the cc.TextFieldTTF with a font name, alignment, dimension and font size
199      * @param {String} placeholder
200      * @param {cc.Size} dimensions
201      * @param {Number} alignment
202      * @param {String} fontName
203      * @param {Number} fontSize
204      * @return {Boolean}
205      * @example
206      * //example
207      * var  textField = new cc.TextFieldTTF();
208      * // When five parameters
209      * textField.initWithPlaceHolder("<click here for input>", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32);
210      * // When three parameters
211      * textField.initWithPlaceHolder("<click here for input>", "Arial", 32);
212      */
213     initWithPlaceHolder:function (placeholder, dimensions, alignment, fontName, fontSize) {
214         switch (arguments.length) {
215             case 5:
216                 if (placeholder)
217                     this.setPlaceHolder(placeholder);
218                 return this.initWithString(this._placeHolder,fontName, fontSize, dimensions, alignment);
219                 break;
220             case 3:
221                 if (placeholder)
222                     this.setPlaceHolder(placeholder);
223                 return this.initWithString(this._placeHolder, arguments[1], arguments[2]);
224                 break;
225             default:
226                 throw "Argument must be non-nil ";
227                 break;
228         }
229     },
230 
231     /**
232      * Input text property
233      * @param {String} text
234      */
235     setString:function (text) {
236         text = String(text);
237         this._inputText = text || "";
238 
239         // if there is no input text, display placeholder instead
240         if (!this._inputText.length){
241             cc.LabelTTF.prototype.setString.call(this, this._placeHolder);
242             this.setColor(this.colorSpaceHolder);
243         } else {
244             cc.LabelTTF.prototype.setString.call(this,this._inputText);
245             this.setColor(this._colorText);
246         }
247         if(cc._renderType === cc._RENDER_TYPE_CANVAS)
248             this._updateTexture();
249         this._charCount = this._inputText.length;
250     },
251 
252     /**
253      * Gets the string
254      * @return {String}
255      */
256     getString:function () {
257         return this._inputText;
258     },
259 
260     /**
261      * Set the place holder. <br />
262      * display this string if string equal "".
263      * @param {String} text
264      */
265     setPlaceHolder:function (text) {
266         this._placeHolder = text || "";
267         if (!this._inputText.length) {
268             cc.LabelTTF.prototype.setString.call(this,this._placeHolder);
269             this.setColor(this.colorSpaceHolder);
270         }
271     },
272 
273     /**
274      * Gets the place holder. <br />
275      * default display string.
276      * @return {String}
277      */
278     getPlaceHolder:function () {
279         return this._placeHolder;
280     },
281 
282     /**
283      * Render function using the canvas 2d context or WebGL context, internal usage only, please do not call this function.
284      * @param {CanvasRenderingContext2D | WebGLRenderingContext} ctx The render context
285      */
286     draw:function (ctx) {
287         //console.log("size",this._contentSize);
288         var context = ctx || cc._renderContext;
289         if (this.delegate && this.delegate.onDraw(this))
290             return;
291 
292         cc.LabelTTF.prototype.draw.call(this, context);
293     },
294 
295     /**
296      * Recursive method that visit its children and draw them.
297      * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx
298      */
299     visit: function(ctx){
300         this._super(ctx);
301     },
302 
303     //////////////////////////////////////////////////////////////////////////
304     // CCIMEDelegate interface
305     //////////////////////////////////////////////////////////////////////////
306     /**
307      * Open keyboard and receive input text.
308      * @return {Boolean}
309      */
310     attachWithIME:function () {
311         return cc.imeDispatcher.attachDelegateWithIME(this);
312     },
313 
314     /**
315      * End text input  and close keyboard.
316      * @return {Boolean}
317      */
318     detachWithIME:function () {
319         return cc.imeDispatcher.detachDelegateWithIME(this);
320     },
321 
322     /**
323      * Return whether to allow attach with IME.
324      * @return {Boolean}
325      */
326     canAttachWithIME:function () {
327         return (this.delegate) ? (!this.delegate.onTextFieldAttachWithIME(this)) : true;
328     },
329 
330     /**
331      * When the delegate detach with IME, this method call by CCIMEDispatcher.
332      */
333     didAttachWithIME:function () {
334     },
335 
336     /**
337      * Return whether to allow detach with IME.
338      * @return {Boolean}
339      */
340     canDetachWithIME:function () {
341         return (this.delegate) ? (!this.delegate.onTextFieldDetachWithIME(this)) : true;
342     },
343 
344     /**
345      * When the delegate detach with IME, this method call by CCIMEDispatcher.
346      */
347     didDetachWithIME:function () {
348     },
349 
350     /**
351      * Delete backward
352      */
353     deleteBackward:function () {
354         var strLen = this._inputText.length;
355         if (strLen == 0)
356             return;
357 
358         // get the delete byte number
359         var deleteLen = 1;    // default, erase 1 byte
360 
361         if (this.delegate && this.delegate.onTextFieldDeleteBackward(this, this._inputText[strLen - deleteLen], deleteLen)) {
362             // delegate don't want delete backward
363             return;
364         }
365 
366         // if delete all text, show space holder string
367         if (strLen <= deleteLen) {
368             this._inputText = "";
369             this._charCount = 0;
370             cc.LabelTTF.prototype.setString.call(this,this._placeHolder);
371             this.setColor(this.colorSpaceHolder);
372             return;
373         }
374 
375         // set new input text
376         this.string = this._inputText.substring(0, strLen - deleteLen);
377     },
378 
379     /**
380      *  Remove delegate
381      */
382     removeDelegate:function () {
383         cc.imeDispatcher.removeDelegate(this);
384     },
385 
386     /**
387      * Append the text. <br />
388      * Input the character.
389      * @param {String} text
390      * @param {Number} len
391      */
392     insertText:function (text, len) {
393         var sInsert = text;
394 
395         // insert \n means input end
396         var pos = sInsert.indexOf('\n');
397         if (pos > -1) {
398             sInsert = sInsert.substring(0, pos);
399         }
400 
401         if (sInsert.length > 0) {
402             if (this.delegate && this.delegate.onTextFieldInsertText(this, sInsert, sInsert.length)) {
403                 // delegate doesn't want insert text
404                 return;
405             }
406 
407             var sText = this._inputText + sInsert;
408             this._charCount = sText.length;
409             this.string = sText;
410         }
411 
412         if (pos == -1)
413             return;
414 
415         // '\n' has inserted,  let delegate process first
416         if (this.delegate && this.delegate.onTextFieldInsertText(this, "\n", 1))
417             return;
418 
419         // if delegate hasn't process, detach with ime as default
420         this.detachWithIME();
421     },
422 
423     /**
424      * Gets the input text.
425      * @return {String}
426      */
427     getContentText:function () {
428         return this._inputText;
429     },
430 
431     //////////////////////////////////////////////////////////////////////////
432     // keyboard show/hide notification
433     //////////////////////////////////////////////////////////////////////////
434     keyboardWillShow:function (info) {
435     },
436     keyboardDidShow:function (info) {
437     },
438     keyboardWillHide:function (info) {
439     },
440     keyboardDidHide:function (info) {
441     }
442 });
443 
444 var _p = cc.TextFieldTTF.prototype;
445 
446 // Extended properties
447 /** @expose */
448 _p.charCount;
449 cc.defineGetterSetter(_p, "charCount", _p.getCharCount);
450 /** @expose */
451 _p.placeHolder;
452 cc.defineGetterSetter(_p, "placeHolder", _p.getPlaceHolder, _p.setPlaceHolder);
453 
454 
455 /**
456  * Please use new TextFieldTTF instead. <br />
457  * Creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size.
458  * @deprecated since v3.0 Please use new TextFieldTTF instead.
459  * @param {String} placeholder
460  * @param {cc.Size} dimensions
461  * @param {Number} alignment
462  * @param {String} fontName
463  * @param {Number} fontSize
464  * @return {cc.TextFieldTTF|Null}
465  * @example
466  * //example
467  * // When five parameters
468  * var textField = cc.TextFieldTTF.create("<click here for input>", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32);
469  * // When three parameters
470  * var textField = cc.TextFieldTTF.create("<click here for input>", "Arial", 32);
471  */
472 cc.TextFieldTTF.create = function (placeholder, dimensions, alignment, fontName, fontSize) {
473     return new cc.TextFieldTTF(placeholder, dimensions, alignment, fontName, fontSize);
474 };
475 
476