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