1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4  Copyright (c) 2012 James Chen
  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  * @constant
 29  * @type Number
 30  */
 31 cc.KEYBOARD_RETURNTYPE_DEFAULT = 0;
 32 
 33 /**
 34  * @constant
 35  * @type Number
 36  */
 37 cc.KEYBOARD_RETURNTYPE_DONE = 1;
 38 
 39 /**
 40  * @constant
 41  * @type Number
 42  */
 43 cc.KEYBOARD_RETURNTYPE_SEND = 2;
 44 
 45 /**
 46  * @constant
 47  * @type Number
 48  */
 49 cc.KEYBOARD_RETURNTYPE_SEARCH = 3;
 50 
 51 /**
 52  * @constant
 53  * @type Number
 54  */
 55 cc.KEYBOARD_RETURNTYPE_GO = 4;
 56 
 57 /**
 58  * The EditBoxInputMode defines the type of text that the user is allowed * to enter.
 59  * @constant
 60  * @type Number
 61  */
 62 cc.EDITBOX_INPUT_MODE_ANY = 0;
 63 
 64 /**
 65  * The user is allowed to enter an e-mail address.
 66  * @constant
 67  * @type Number
 68  */
 69 cc.EDITBOX_INPUT_MODE_EMAILADDR = 1;
 70 
 71 /**
 72  * The user is allowed to enter an integer value.
 73  * @constant
 74  * @type Number
 75  */
 76 cc.EDITBOX_INPUT_MODE_NUMERIC = 2;
 77 
 78 /**
 79  * The user is allowed to enter a phone number.
 80  * @constant
 81  * @type Number
 82  */
 83 cc.EDITBOX_INPUT_MODE_PHONENUMBER = 3;
 84 
 85 /**
 86  * The user is allowed to enter a URL.
 87  * @constant
 88  * @type Number
 89  */
 90 cc.EDITBOX_INPUT_MODE_URL = 4;
 91 
 92 /**
 93  * The user is allowed to enter a real number value.
 94  * This extends kEditBoxInputModeNumeric by allowing a decimal point.
 95  * @constant
 96  * @type Number
 97  */
 98 cc.EDITBOX_INPUT_MODE_DECIMAL = 5;
 99 
100 /**
101  * The user is allowed to enter any text, except for line breaks.
102  * @constant
103  * @type Number
104  */
105 cc.EDITBOX_INPUT_MODE_SINGLELINE = 6;
106 
107 /**
108  * Indicates that the text entered is confidential data that should be
109  * obscured whenever possible. This implies EDIT_BOX_INPUT_FLAG_SENSITIVE.
110  * @constant
111  * @type Number
112  */
113 cc.EDITBOX_INPUT_FLAG_PASSWORD = 0;
114 
115 /**
116  * Indicates that the text entered is sensitive data that the
117  * implementation must never store into a dictionary or table for use
118  * in predictive, auto-completing, or other accelerated input schemes.
119  * A credit card number is an example of sensitive data.
120  * @constant
121  * @type Number
122  */
123 cc.EDITBOX_INPUT_FLAG_SENSITIVE = 1;
124 
125 /**
126  * This flag is a hint to the implementation that during text editing,
127  * the initial letter of each word should be capitalized.
128  * @constant
129  * @type Number
130  */
131 cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_WORD = 2;
132 
133 /**
134  * This flag is a hint to the implementation that during text editing,
135  * the initial letter of each sentence should be capitalized.
136  * @constant
137  * @type Number
138  */
139 cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_SENTENCE = 3;
140 
141 /**
142  * Capitalize all characters automatically.
143  * @constant
144  * @type Number
145  */
146 cc.EDITBOX_INPUT_FLAG_INITIAL_CAPS_ALL_CHARACTERS = 4;
147 
148 cc.EditBoxDelegate = cc.Class.extend({
149     /**
150      * This method is called when an edit box gains focus after keyboard is shown.
151      * @param {cc.EditBox} sender
152      */
153     editBoxEditingDidBegin: function (sender) {
154     },
155 
156     /**
157      * This method is called when an edit box loses focus after keyboard is hidden.
158      * @param {cc.EditBox} sender
159      */
160     editBoxEditingDidEnd: function (sender) {
161     },
162 
163     /**
164      * This method is called when the edit box text was changed.
165      * @param {cc.EditBox} sender
166      * @param {String} text
167      */
168     editBoxTextChanged: function (sender, text) {
169     },
170 
171     /**
172      * This method is called when the return button was pressed or the outside area of keyboard was touched.
173      * @param {cc.EditBox} sender
174      */
175     editBoxReturn: function (sender) {
176     }
177 });
178 
179 /**
180  * <p>cc.EditBox is a brief Class for edit box.<br/>
181  * You can use this widget to gather small amounts of text from the user.</p>
182  *
183  * @class
184  * @extends cc.ControlButton
185  *
186  * @property {String}   string                  - Content string of edit box
187  * @property {String}   maxLength               - Max length of the content string
188  * @property {String}   font                    - <@writeonly> Config font of edit box
189  * @property {String}   fontName                - <@writeonly> Config font name of edit box
190  * @property {Number}   fontSize                - <@writeonly> Config font size of edit box
191  * @property {cc.Color} fontColor               - <@writeonly> Config font color of edit box
192  * @property {String}   placeHolder             - Place holder of edit box
193  * @property {String}   placeHolderFont         - <@writeonly> Config font of place holder
194  * @property {String}   placeHolderFontName     - <@writeonly> Config font name of place holder
195  * @property {Number}   placeHolderFontSize     - <@writeonly> Config font size of place holder
196  * @property {cc.Color} placeHolderFontColor    - <@writeonly> Config font color of place holder
197  * @property {Number}   inputFlag               - <@writeonly> Input flag of edit box, one of the EditBoxInputFlag constants. e.g.cc.EDITBOX_INPUT_FLAG_PASSWORD
198  * @property {Object}   delegate                - <@writeonly> Delegate of edit box
199  * @property {Number}   inputMode               - <@writeonly> Input mode of the edit box. Value should be one of the EditBoxInputMode constants.
200  * @property {Number}   returnType              - <@writeonly> Return type of edit box, value should be one of the KeyboardReturnType constants.
201  *
202  */
203 cc.EditBox = cc.ControlButton.extend({
204     _domInputSprite: null,
205 
206     _delegate: null,
207     _editBoxInputMode: cc.EDITBOX_INPUT_MODE_ANY,
208     _editBoxInputFlag: cc.EDITBOX_INPUT_FLAG_SENSITIVE,
209     _keyboardReturnType: cc.KEYBOARD_RETURNTYPE_DEFAULT,
210 
211     _text: "",
212     _placeholderText: "",
213     _textColor: null,
214     _placeholderColor: null,
215     _maxLength: 50,
216     _adjustHeight: 18,
217 
218     _edTxt: null,
219     _edFontSize: 14,
220     _edFontName: "Arial",
221 
222     _placeholderFontName: "",
223     _placeholderFontSize: 14,
224 
225     _tooltip: false,
226     _className: "EditBox",
227 
228     /**
229      * * Constructor.
230      * */
231     ctor: function (boxSize) {
232         cc.ControlButton.prototype.ctor.call(this);
233 
234         this._textColor = cc.color.WHITE;
235         this._placeholderColor = cc.color.GRAY;
236         this.setContentSize(boxSize);
237         var tmpDOMSprite = this._domInputSprite = new cc.Sprite();
238         tmpDOMSprite.draw = function () {
239         };                           //redefine draw function
240         this.addChild(tmpDOMSprite);
241         var selfPointer = this;
242         var tmpEdTxt = this._edTxt = cc.newElement("input");
243         tmpEdTxt.type = "text";
244         tmpEdTxt.style.fontSize = this._edFontSize + "px";
245         tmpEdTxt.style.color = "#000000";
246         tmpEdTxt.style.border = 0;
247         tmpEdTxt.style.background = "transparent";
248         //tmpEdTxt.style.paddingLeft = "2px";
249         tmpEdTxt.style.width = "100%";
250         tmpEdTxt.style.height = "100%";
251         tmpEdTxt.style.active = 0;
252         tmpEdTxt.style.outline = "medium";
253 
254         // TODO the event listener will be remove when EditBox removes from parent.
255         cc._addEventListener(tmpEdTxt, "input", function () {
256             if (selfPointer._delegate && selfPointer._delegate.editBoxTextChanged)
257                 selfPointer._delegate.editBoxTextChanged(selfPointer, this.value);
258         });
259         cc._addEventListener(tmpEdTxt, "keypress", function (e) {
260             if (e.keyCode === cc.KEY.enter) {
261                 e.stopPropagation();
262                 e.preventDefault();
263                 cc._canvas.focus();
264             }
265         });
266         cc._addEventListener(tmpEdTxt, "focus", function () {
267             if (this.value == selfPointer._placeholderText) {
268                 this.value = "";
269                 this.style.fontSize = selfPointer._edFontSize + "px";
270                 this.style.color = cc.colorToHex(selfPointer._textColor);
271             }
272             if (selfPointer._delegate && selfPointer._delegate.editBoxEditingDidBegin)
273                 selfPointer._delegate.editBoxEditingDidBegin(selfPointer);
274         });
275         cc._addEventListener(tmpEdTxt, "blur", function () {
276             if (this.value == "") {
277                 this.value = selfPointer._placeholderText;
278                 this.style.fontSize = selfPointer._placeholderFontSize + "px";
279                 this.style.color = cc.colorToHex(selfPointer._placeholderColor);
280             }
281             if (selfPointer._delegate && selfPointer._delegate.editBoxEditingDidEnd)
282                 selfPointer._delegate.editBoxEditingDidEnd(selfPointer);
283             if (selfPointer._delegate && selfPointer._delegate.editBoxReturn)
284                 selfPointer._delegate.editBoxReturn(selfPointer);
285         });
286 
287         cc.DOM.convert(tmpDOMSprite);
288         tmpDOMSprite.dom.appendChild(tmpEdTxt);
289         tmpDOMSprite.dom.showTooltipDiv = false;
290         tmpDOMSprite.dom.style.width = (boxSize.width - 6) + "px";
291         tmpDOMSprite.dom.style.height = (boxSize.height - 6) + "px";
292 
293         //this._domInputSprite.dom.style.borderWidth = "1px";
294         //this._domInputSprite.dom.style.borderStyle = "solid";
295         //this._domInputSprite.dom.style.borderRadius = "8px";
296         tmpDOMSprite.canvas.remove();
297     },
298 
299     /**
300      * Set the font.
301      * @param {String} fontName  The font name.
302      * @param {Number} fontSize  The font size.
303      */
304     setFont: function (fontName, fontSize) {
305         this._edFontSize = fontSize;
306         this._edFontName = fontName;
307         this._setFontToEditBox();
308     },
309 
310     _setFont: function (fontStyle) {
311         var res = cc.LabelTTF._fontStyleRE.exec(fontStyle);
312         if (res) {
313             this._edFontSize = parseInt(res[1]);
314             this._edFontName = res[2];
315             this._setFontToEditBox();
316         }
317     },
318 
319     /**
320      * set fontName
321      * @param {String} fontName
322      */
323     setFontName: function (fontName) {
324         this._edFontName = fontName;
325         this._setFontToEditBox();
326     },
327 
328     /**
329      * set fontSize
330      * @param {Number} fontSize
331      */
332     setFontSize: function (fontSize) {
333         this._edFontSize = fontSize;
334         this._setFontToEditBox();
335     },
336 
337     _setFontToEditBox: function () {
338         if (this._edTxt.value != this._placeholderText) {
339             this._edTxt.style.fontFamily = this._edFontName;
340             this._edTxt.style.fontSize = this._edFontSize + "px";
341         }
342     },
343 
344     /**
345      *  Set the text entered in the edit box.
346      * @param {string} text The given text.
347      */
348     setText: function (text) {
349         if (text != null) {
350             if (text == "") {
351                 this._edTxt.value = this._placeholderText;
352                 this._edTxt.style.color = cc.colorToHex(this._placeholderColor);
353             } else {
354                 this._edTxt.value = text;
355                 this._edTxt.style.color = cc.colorToHex(this._textColor);
356             }
357         }
358     },
359 
360     /**
361      * Set the font color of the widget's text.
362      * @param {cc.Color} color
363      */
364     setFontColor: function (color) {
365         this._textColor = color;
366         if (this._edTxt.value != this._placeholderText) {
367             this._edTxt.style.color = cc.colorToHex(color);
368         }
369     },
370 
371     /**
372      * <p>
373      * Sets the maximum input length of the edit box. <br/>
374      * Setting this value enables multiline input mode by default.
375      * </p>
376      * @param {Number} maxLength The maximum length.
377      */
378     setMaxLength: function (maxLength) {
379         if (!isNaN(maxLength) && maxLength > 0) {
380             this._maxLength = maxLength;
381             this._edTxt.maxLength = maxLength;
382         }
383     },
384 
385     /**
386      * Gets the maximum input length of the edit box.
387      * @return {Number} Maximum input length.
388      */
389     getMaxLength: function () {
390         return this._maxLength;
391     },
392 
393     /**
394      * Set a text in the edit box that acts as a placeholder when an edit box is empty.
395      * @param {string} text The given text.
396      */
397     setPlaceHolder: function (text) {
398         if (text != null) {
399             var oldPlaceholderText = this._placeholderText;
400             this._placeholderText = text;
401             if (this._edTxt.value == oldPlaceholderText) {
402                 this._edTxt.value = text;
403                 this._edTxt.style.color = cc.colorToHex(this._placeholderColor);
404                 this._setPlaceholderFontToEditText();
405             }
406         }
407     },
408 
409     /**
410      * Set the placeholder's font.
411      * @param {String} fontName
412      * @param {Number} fontSize
413      */
414     setPlaceholderFont: function (fontName, fontSize) {
415         this._placeholderFontName = fontName;
416         this._placeholderFontSize = fontSize;
417         this._setPlaceholderFontToEditText();
418     },
419     _setPlaceholderFont: function (fontStyle) {
420         var res = cc.LabelTTF._fontStyleRE.exec(fontStyle);
421         if (res) {
422             this._placeholderFontName = res[2];
423             this._placeholderFontSize = parseInt(res[1]);
424             this._setPlaceholderFontToEditText();
425         }
426     },
427 
428     /**
429      * Set the placeholder's fontName.
430      * @param {String} fontName
431      */
432     setPlaceholderFontName: function (fontName) {
433         this._placeholderFontName = fontName;
434         this._setPlaceholderFontToEditText();
435     },
436 
437     /**
438      * Set the placeholder's fontSize.
439      * @param {Number} fontSize
440      */
441     setPlaceholderFontSize: function (fontSize) {
442         this._placeholderFontSize = fontSize;
443         this._setPlaceholderFontToEditText();
444     },
445 
446     _setPlaceholderFontToEditText: function () {
447         if (this._edTxt.value == this._placeholderText) {
448             this._edTxt.style.fontFamily = this._placeholderFontName;
449             this._edTxt.style.fontSize = this._placeholderFontSize + "px";
450         }
451     },
452 
453     /**
454      * Set the font color of the placeholder text when the edit box is empty.
455      * @param {cc.Color} color
456      */
457     setPlaceholderFontColor: function (color) {
458         this._placeholderColor = color;
459         if (this._edTxt.value == this._placeholderText) {
460             this._edTxt.style.color = cc.colorToHex(color);
461         }
462     },
463 
464     /**
465      * Set the input flags that are to be applied to the edit box.
466      * @param {Number} inputFlag One of the EditBoxInputFlag constants.
467      * e.g.cc.EDITBOX_INPUT_FLAG_PASSWORD
468      */
469     setInputFlag: function (inputFlag) {
470         this._editBoxInputFlag = inputFlag;
471         if (inputFlag == cc.EDITBOX_INPUT_FLAG_PASSWORD)
472             this._edTxt.type = "password";
473         else
474             this._edTxt.type = "text";
475     },
476 
477     /**
478      * Gets the  input string of the edit box.
479      * @return {string}
480      */
481     getText: function () {
482         return this._edTxt.value;
483     },
484 
485     /**
486      * Init edit box with specified size.
487      * @param {cc.Size} size
488      * @param {cc.Color | cc.Scale9Sprite} normal9SpriteBg
489      */
490     initWithSizeAndBackgroundSprite: function (size, normal9SpriteBg) {
491         if (this.initWithBackgroundSprite(normal9SpriteBg)) {
492             this._domInputSprite.x = 3;
493             this._domInputSprite.y = 3;
494 
495             this.setZoomOnTouchDown(false);
496             this.setPreferredSize(size);
497             this.x = 0;
498             this.y = 0;
499             this._addTargetWithActionForControlEvent(this, this.touchDownAction, cc.CONTROL_EVENT_TOUCH_UP_INSIDE);
500             return true;
501         }
502         return false;
503     },
504 
505     /* override functions */
506     /**
507      * Set the delegate for edit box.
508      */
509     setDelegate: function (delegate) {
510         this._delegate = delegate;
511     },
512 
513     /**
514      * Get a text in the edit box that acts as a placeholder when an
515      * edit box is empty.
516      * @return {String}
517      */
518     getPlaceHolder: function () {
519         return this._placeholderText;
520     },
521 
522     /**
523      * Set the input mode of the edit box.
524      * @param {Number} inputMode One of the EditBoxInputMode constants.
525      */
526     setInputMode: function (inputMode) {
527         this._editBoxInputMode = inputMode;
528     },
529 
530     /**
531      * Set the return type that are to be applied to the edit box.
532      * @param {Number} returnType One of the CCKeyboardReturnType constants.
533      */
534     setReturnType: function (returnType) {
535         this._keyboardReturnType = returnType;
536     },
537 
538     keyboardWillShow: function (info) {
539         var rectTracked = cc.EditBox.getRect(this);
540         // some adjustment for margin between the keyboard and the edit box.
541         rectTracked.y -= 4;
542         // if the keyboard area doesn't intersect with the tracking node area, nothing needs to be done.
543         if (!rectTracked.intersectsRect(info.end)) {
544             cc.log("needn't to adjust view layout.");
545             return;
546         }
547 
548         // assume keyboard at the bottom of screen, calculate the vertical adjustment.
549         this._adjustHeight = info.end.getMaxY() - rectTracked.getMinY();
550         // CCLOG("CCEditBox:needAdjustVerticalPosition(%f)", m_fAdjustHeight);
551 
552         //callback
553     },
554     keyboardDidShow: function (info) {
555     },
556     keyboardWillHide: function (info) {
557         //if (m_pEditBoxImpl != NULL) {
558         //    m_pEditBoxImpl->doAnimationWhenKeyboardMove(info.duration, -m_fAdjustHeight);
559         //}
560     },
561     keyboardDidHide: function (info) {
562     },
563 
564     touchDownAction: function (sender, controlEvent) {
565         //this._editBoxImpl.openKeyboard();
566     },
567 
568     //HTML5 Only
569     initWithBackgroundColor: function (size, bgColor) {
570         this._edWidth = size.width;
571         this.dom.style.width = this._edWidth.toString() + "px";
572         this._edHeight = size.height;
573         this.dom.style.height = this._edHeight.toString() + "px";
574         this.dom.style.backgroundColor = cc.colorToHex(bgColor);
575     }
576 });
577 
578 var _p = cc.EditBox.prototype;
579 
580 // Extended properties
581 /** @expose */
582 _p.font;
583 cc.defineGetterSetter(_p, "font", null, _p._setFont);
584 /** @expose */
585 _p.fontName;
586 cc.defineGetterSetter(_p, "fontName", null, _p.setFontName);
587 /** @expose */
588 _p.fontSize;
589 cc.defineGetterSetter(_p, "fontSize", null, _p.setFontSize);
590 /** @expose */
591 _p.fontColor;
592 cc.defineGetterSetter(_p, "fontColor", null, _p.setFontColor);
593 /** @expose */
594 _p.string;
595 cc.defineGetterSetter(_p, "string", _p.getText, _p.setText);
596 /** @expose */
597 _p.maxLength;
598 cc.defineGetterSetter(_p, "maxLength", _p.getMaxLength, _p.setMaxLength);
599 /** @expose */
600 _p.placeHolder;
601 cc.defineGetterSetter(_p, "placeHolder", _p.getPlaceHolder, _p.setPlaceHolder);
602 /** @expose */
603 _p.placeHolderFont;
604 cc.defineGetterSetter(_p, "placeHolderFont", null, _p._setPlaceholderFont);
605 /** @expose */
606 _p.placeHolderFontName;
607 cc.defineGetterSetter(_p, "placeHolderFontName", null, _p.setPlaceholderFontName);
608 /** @expose */
609 _p.placeHolderFontSize;
610 cc.defineGetterSetter(_p, "placeHolderFontSize", null, _p.setPlaceholderFontSize);
611 /** @expose */
612 _p.placeHolderFontColor;
613 cc.defineGetterSetter(_p, "placeHolderFontColor", null, _p.setPlaceholderFontColor);
614 /** @expose */
615 _p.inputFlag;
616 cc.defineGetterSetter(_p, "inputFlag", null, _p.setInputFlag);
617 /** @expose */
618 _p.delegate;
619 cc.defineGetterSetter(_p, "delegate", null, _p.setDelegate);
620 /** @expose */
621 _p.inputMode;
622 cc.defineGetterSetter(_p, "inputMode", null, _p.setInputMode);
623 /** @expose */
624 _p.returnType;
625 cc.defineGetterSetter(_p, "returnType", null, _p.setReturnType);
626 
627 _p = null;
628 
629 cc.EditBox.getRect = function (node) {
630     var contentSize = node.getContentSize();
631     var rect = cc.rect(0, 0, contentSize.width, contentSize.height);
632     return cc.RectApplyAffineTransform(rect, node.nodeToWorldTransform());
633 };
634 
635 /**
636  * create a edit box with size and background-color or
637  * @param {cc.Size} size
638  * @param {cc.Scale9Sprite } normal9SpriteBg
639  * @param {cc.Scale9Sprite } [press9SpriteBg]
640  * @param {cc.Scale9Sprite } [disabled9SpriteBg]
641  */
642 cc.EditBox.create = function (size, normal9SpriteBg, press9SpriteBg, disabled9SpriteBg) {
643     var edbox = new cc.EditBox(size);
644     if (edbox.initWithSizeAndBackgroundSprite(size, normal9SpriteBg)) {
645         if (press9SpriteBg)
646             edbox.setBackgroundSpriteForState(press9SpriteBg, cc.CONTROL_STATE_HIGHLIGHTED);
647 
648         if (disabled9SpriteBg)
649             edbox.setBackgroundSpriteForState(disabled9SpriteBg, cc.CONTROL_STATE_DISABLED);
650     }
651     return edbox;
652 };
653 
654 
655 
656 
657