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     _lens:null,
111     _inputText:"",
112     _placeHolder:"",
113     _charCount:0,
114     _className:"TextFieldTTF",
115 
116     /**
117      * Constructor function, override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function. <br />
118      * creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size.
119      * @param {String} placeholder
120      * @param {cc.Size} dimensions
121      * @param {Number} alignment
122      * @param {String} fontName
123      * @param {Number} fontSize
124      */
125     ctor:function (placeholder, dimensions, alignment, fontName, fontSize) {
126         this.colorSpaceHolder = cc.color(127, 127, 127);
127         cc.imeDispatcher.addDelegate(this);
128         cc.LabelTTF.prototype.ctor.call(this);
129 
130         if(fontSize !== undefined){
131             this.initWithPlaceHolder("", dimensions, alignment, fontName, fontSize);
132             if(placeholder)
133                 this.setPlaceHolder(placeholder);
134         }else if(fontName === undefined && alignment !== undefined){
135             this.initWithString("", arguments[1], arguments[2]);
136             if(placeholder)
137                 this.setPlaceHolder(placeholder);
138         }
139     },
140 
141     /**
142      * Gets the delegate.
143      * @return {cc.Node}
144      */
145     getDelegate:function () {
146         return this.delegate;
147     },
148 
149     /**
150      * Set the delegate.
151      * @param {cc.Node} value
152      */
153     setDelegate:function (value) {
154         this.delegate = value;
155     },
156 
157     /**
158      * Gets the char count.
159      * @return {Number}
160      */
161     getCharCount:function () {
162         return this._charCount;
163     },
164 
165     /**
166      * Gets the color of space holder.
167      * @return {cc.Color}
168      */
169     getColorSpaceHolder:function () {
170         return this.colorSpaceHolder;
171     },
172 
173     /**
174      * Gets the color of space holder.
175      * @param {cc.Color} value
176      */
177     setColorSpaceHolder:function (value) {
178         this.colorSpaceHolder = value;
179     },
180 
181     /**
182      * Initializes the cc.TextFieldTTF with a font name, alignment, dimension and font size
183      * @param {String} placeholder
184      * @param {cc.Size} dimensions
185      * @param {Number} alignment
186      * @param {String} fontName
187      * @param {Number} fontSize
188      * @return {Boolean}
189      * @example
190      * //example
191      * var  textField = new cc.TextFieldTTF();
192      * // When five parameters
193      * textField.initWithPlaceHolder("<click here for input>", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32);
194      * // When three parameters
195      * textField.initWithPlaceHolder("<click here for input>", "Arial", 32);
196      */
197     initWithPlaceHolder:function (placeholder, dimensions, alignment, fontName, fontSize) {
198         switch (arguments.length) {
199             case 5:
200                 if (placeholder) {
201                     this.setPlaceHolder(placeholder);
202                 }
203                 return this.initWithString(this._placeHolder,fontName, fontSize, dimensions, alignment);
204                 break;
205             case 3:
206                 if (placeholder) {
207                     this.setPlaceHolder(placeholder);
208                 }
209                 return this.initWithString(this._placeHolder, arguments[1], arguments[2]);
210                 break;
211             default:
212                 throw "Argument must be non-nil ";
213                 break;
214         }
215     },
216 
217     /**
218      * Input text property
219      * @param {String} text
220      */
221     setString:function (text) {
222         text = String(text);
223         this._inputText = text || "";
224 
225         // if there is no input text, display placeholder instead
226         if (!this._inputText.length)
227             cc.LabelTTF.prototype.setString.call(this, this._placeHolder);
228         else
229             cc.LabelTTF.prototype.setString.call(this,this._inputText);
230         this._charCount = this._inputText.length;
231     },
232 
233     /**
234      * Gets the string
235      * @return {String}
236      */
237     getString:function () {
238         return this._inputText;
239     },
240 
241     /**
242      * Set the place holder. <br />
243      * display this string if string equal "".
244      * @param {String} text
245      */
246     setPlaceHolder:function (text) {
247         this._placeHolder = text || "";
248         if (!this._inputText.length) {
249             cc.LabelTTF.prototype.setString.call(this,this._placeHolder);
250         }
251     },
252 
253     /**
254      * Gets the place holder. <br />
255      * default display string.
256      * @return {String}
257      */
258     getPlaceHolder:function () {
259         return this._placeHolder;
260     },
261 
262     /**
263      * Render function using the canvas 2d context or WebGL context, internal usage only, please do not call this function.
264      * @param {CanvasRenderingContext2D | WebGLRenderingContext} ctx The render context
265      */
266     draw:function (ctx) {
267         //console.log("size",this._contentSize);
268         var context = ctx || cc._renderContext;
269         if (this.delegate && this.delegate.onDraw(this))
270             return;
271 
272         if (this._inputText && this._inputText.length > 0) {
273             cc.LabelTTF.prototype.draw.call(this, context);
274             return;
275         }
276 
277         // draw placeholder
278         var color = this.color;
279         this.color = this.colorSpaceHolder;
280         if(cc._renderType === cc._RENDER_TYPE_CANVAS)
281             this._updateTexture();
282         cc.LabelTTF.prototype.draw.call(this, context);
283         this.color = color;
284     },
285 
286     /**
287      * Recursive method that visit its children and draw them.
288      * @param {CanvasRenderingContext2D|WebGLRenderingContext} ctx
289      */
290     visit: function(ctx){
291         this._super(ctx);
292     },
293 
294     //////////////////////////////////////////////////////////////////////////
295     // CCIMEDelegate interface
296     //////////////////////////////////////////////////////////////////////////
297     /**
298      * Open keyboard and receive input text.
299      * @return {Boolean}
300      */
301     attachWithIME:function () {
302         return cc.imeDispatcher.attachDelegateWithIME(this);
303     },
304 
305     /**
306      * End text input  and close keyboard.
307      * @return {Boolean}
308      */
309     detachWithIME:function () {
310         return cc.imeDispatcher.detachDelegateWithIME(this);
311     },
312 
313     /**
314      * Return whether to allow attach with IME.
315      * @return {Boolean}
316      */
317     canAttachWithIME:function () {
318         return (this.delegate) ? (!this.delegate.onTextFieldAttachWithIME(this)) : true;
319     },
320 
321     /**
322      * When the delegate detach with IME, this method call by CCIMEDispatcher.
323      */
324     didAttachWithIME:function () {
325     },
326 
327     /**
328      * Return whether to allow detach with IME.
329      * @return {Boolean}
330      */
331     canDetachWithIME:function () {
332         return (this.delegate) ? (!this.delegate.onTextFieldDetachWithIME(this)) : true;
333     },
334 
335     /**
336      * When the delegate detach with IME, this method call by CCIMEDispatcher.
337      */
338     didDetachWithIME:function () {
339     },
340 
341     /**
342      * Delete backward
343      */
344     deleteBackward:function () {
345         var strLen = this._inputText.length;
346         if (strLen == 0)
347             return;
348 
349         // get the delete byte number
350         var deleteLen = 1;    // default, erase 1 byte
351 
352         if (this.delegate && this.delegate.onTextFieldDeleteBackward(this, this._inputText[strLen - deleteLen], deleteLen)) {
353             // delegate don't want delete backward
354             return;
355         }
356 
357         // if delete all text, show space holder string
358         if (strLen <= deleteLen) {
359             this._inputText = "";
360             this._charCount = 0;
361             cc.LabelTTF.prototype.setString.call(this,this._placeHolder);
362             return;
363         }
364 
365         // set new input text
366         this.string = this._inputText.substring(0, strLen - deleteLen);
367     },
368 
369     /**
370      *  Remove delegate
371      */
372     removeDelegate:function () {
373         cc.imeDispatcher.removeDelegate(this);
374     },
375 
376     /**
377      * Append the text. <br />
378      * Input the character.
379      * @param {String} text
380      * @param {Number} len
381      */
382     insertText:function (text, len) {
383         var sInsert = text;
384 
385         // insert \n means input end
386         var pos = sInsert.indexOf('\n');
387         if (pos > -1) {
388             sInsert = sInsert.substring(0, pos);
389         }
390 
391         if (sInsert.length > 0) {
392             if (this.delegate && this.delegate.onTextFieldInsertText(this, sInsert, sInsert.length)) {
393                 // delegate doesn't want insert text
394                 return;
395             }
396 
397             var sText = this._inputText + sInsert;
398             this._charCount = sText.length;
399             this.string = sText;
400         }
401 
402         if (pos == -1)
403             return;
404 
405         // '\n' has inserted,  let delegate process first
406         if (this.delegate && this.delegate.onTextFieldInsertText(this, "\n", 1))
407             return;
408 
409         // if delegate hasn't process, detach with ime as default
410         this.detachWithIME();
411     },
412 
413     /**
414      * Gets the input text.
415      * @return {String}
416      */
417     getContentText:function () {
418         return this._inputText;
419     },
420 
421     //////////////////////////////////////////////////////////////////////////
422     // keyboard show/hide notification
423     //////////////////////////////////////////////////////////////////////////
424     keyboardWillShow:function (info) {
425     },
426     keyboardDidShow:function (info) {
427     },
428     keyboardWillHide:function (info) {
429     },
430     keyboardDidHide:function (info) {
431     }
432 });
433 
434 var _p = cc.TextFieldTTF.prototype;
435 
436 // Extended properties
437 /** @expose */
438 _p.charCount;
439 cc.defineGetterSetter(_p, "charCount", _p.getCharCount);
440 /** @expose */
441 _p.placeHolder;
442 cc.defineGetterSetter(_p, "placeHolder", _p.getPlaceHolder, _p.setPlaceHolder);
443 
444 
445 /**
446  * Please use new TextFieldTTF instead. <br />
447  * Creates a cc.TextFieldTTF from a fontName, alignment, dimension and font size.
448  * @deprecated since v3.0 Please use new TextFieldTTF instead.
449  * @param {String} placeholder
450  * @param {cc.Size} dimensions
451  * @param {Number} alignment
452  * @param {String} fontName
453  * @param {Number} fontSize
454  * @return {cc.TextFieldTTF|Null}
455  * @example
456  * //example
457  * // When five parameters
458  * var textField = cc.TextFieldTTF.create("<click here for input>", cc.size(100,50), cc.TEXT_ALIGNMENT_LEFT,"Arial", 32);
459  * // When three parameters
460  * var textField = cc.TextFieldTTF.create("<click here for input>", "Arial", 32);
461  */
462 cc.TextFieldTTF.create = function (placeholder, dimensions, alignment, fontName, fontSize) {
463     return new cc.TextFieldTTF(placeholder, dimensions, alignment, fontName, fontSize);
464 };
465 
466