1 /****************************************************************************
  2  Copyright (c) 2011-2012 cocos2d-x.org
  3  Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5  http://www.cocos2d-x.org
  6 
  7  Permission is hereby granted, free of charge, to any person obtaining a copy
  8  of this software and associated documentation files (the "Software"), to deal
  9  in the Software without restriction, including without limitation the rights
 10  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11  copies of the Software, and to permit persons to whom the Software is
 12  furnished to do so, subject to the following conditions:
 13 
 14  The above copyright notice and this permission notice shall be included in
 15  all copies or substantial portions of the Software.
 16 
 17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23  THE SOFTWARE.
 24  ****************************************************************************/
 25 
 26 /**
 27  * ccui.RichElement is the base class of RichElementText, RichElementImage etc. It has type, tag, color and opacity attributes.
 28  * @class
 29  * @extends ccui.Class
 30  */
 31 ccui.RichElement = ccui.Class.extend(/** @lends ccui.RichElement# */{
 32     _type: 0,
 33     _tag: 0,
 34     _color: null,
 35     _opacity:0,
 36     /**
 37      * Constructor of ccui.RichElement
 38      */
 39     ctor: function (tag, color, opacity) {
 40         this._type = 0;
 41         this._tag = tag || 0;
 42         this._color = cc.color(255, 255, 255, 255);
 43         if (color) {
 44             this._color.r = color.r;
 45             this._color.g = color.g;
 46             this._color.b = color.b;
 47         }
 48         this._opacity = opacity || 0;
 49         if(opacity === undefined) {
 50             this._color.a = color.a;
 51         }
 52         else {
 53             this._color.a = opacity;
 54         }
 55     }
 56 });
 57 
 58 /**
 59  * The text element for RichText, it has text, fontName, fontSize attributes.
 60  * @class
 61  * @extends ccui.RichElement
 62  */
 63 ccui.RichElementText = ccui.RichElement.extend(/** @lends ccui.RichElementText# */{
 64     _text: "",
 65     _fontName: "",
 66     _fontSize: 0,
 67     /** @type cc.FontDefinition */
 68     _fontDefinition: null,
 69     /**
 70      * Usage Example using FontDefinition:
 71      *
 72      * var rtEl  = new ccui.RichElementText("tag", new cc.FontDefinition({
 73      *                              fillStyle: cc.color.BLACK,
 74      *                              fontName: "Arial",
 75      *                              fontSize: 12,
 76      *                              fontWeight: "bold",
 77      *                              fontStyle: "normal",
 78      *                              lineHeight: 14
 79      *                          }), 255, "Some Text");
 80      *
 81      * Constructor of ccui.RichElementText
 82      * @param {Number} tag
 83      * @param {cc.Color|cc.FontDefinition} colorOrFontDef
 84      * @param {Number} opacity
 85      * @param {String} text
 86      * @param {String} fontName
 87      * @param {Number} fontSize
 88      */
 89     ctor: function (tag, colorOrFontDef, opacity, text, fontName, fontSize) {
 90         var color = colorOrFontDef;
 91         if (colorOrFontDef && colorOrFontDef instanceof cc.FontDefinition) {
 92             color = colorOrFontDef.fillStyle;
 93             fontName = colorOrFontDef.fontName;
 94             fontSize = colorOrFontDef.fontSize;
 95             this._fontDefinition = colorOrFontDef;
 96         }
 97         ccui.RichElement.prototype.ctor.call(this, tag, color, opacity);
 98         this._type = ccui.RichElement.TEXT;
 99         this._text = text;
100         this._fontName = fontName;
101         this._fontSize = fontSize;
102     }
103 });
104 
105 /**
106  * Create a richElementText
107  * @deprecated since v3.0, please use new ccui.RichElementText() instead.
108  * @param {Number} tag
109  * @param {cc.Color} color
110  * @param {Number} opacity
111  * @param {String} text
112  * @param {String} fontName
113  * @param {Number} fontSize
114  * @returns {ccui.RichElementText}
115  */
116 ccui.RichElementText.create = function (tag, color, opacity, text, fontName, fontSize) {
117     return new ccui.RichElementText(tag, color, opacity, text, fontName, fontSize);
118 };
119 
120 /**
121  * The image element for RichText, it has filePath, textureRect, textureType attributes.
122  * @class
123  * @extends ccui.RichElement
124  */
125 ccui.RichElementImage = ccui.RichElement.extend(/** @lends ccui.RichElementImage# */{
126     _filePath: "",
127     _textureRect: null,
128     _textureType: 0,
129 
130     /**
131      * Constructor of ccui.RichElementImage
132      * @param {Number} tag
133      * @param {cc.Color} color
134      * @param {Number} opacity
135      * @param {String} filePath
136      */
137     ctor: function (tag, color, opacity, filePath) {
138         ccui.RichElement.prototype.ctor.call(this, tag, color, opacity);
139         this._type = ccui.RichElement.IMAGE;
140         this._filePath = filePath || "";
141         this._textureRect = cc.rect(0, 0, 0, 0);
142         this._textureType = 0;
143     }
144 });
145 
146 /**
147  * Create a richElementImage
148  * @deprecated since v3.0, please use new ccui.RichElementImage() instead.
149  * @param {Number} tag
150  * @param {cc.Color} color
151  * @param {Number} opacity
152  * @param {String} filePath
153  * @returns {ccui.RichElementImage}
154  */
155 ccui.RichElementImage.create = function (tag, color, opacity, filePath) {
156     return new ccui.RichElementImage(tag, color, opacity, filePath);
157 };
158 
159 /**
160  * The custom node element for RichText.
161  * @class
162  * @extends ccui.RichElement
163  */
164 ccui.RichElementCustomNode = ccui.RichElement.extend(/** @lends ccui.RichElementCustomNode# */{
165     _customNode: null,
166 
167     /**
168      * Constructor of ccui.RichElementCustomNode
169      * @param {Number} tag
170      * @param {cc.Color} color
171      * @param {Number} opacity
172      * @param {cc.Node} customNode
173      */
174     ctor: function (tag, color, opacity, customNode) {
175         ccui.RichElement.prototype.ctor.call(this, tag, color, opacity);
176         this._type = ccui.RichElement.CUSTOM;
177         this._customNode = customNode || null;
178     }
179 });
180 
181 /**
182  * Create a richElementCustomNode
183  * @deprecated since v3.0, please use new ccui.RichElementCustomNode() instead.
184  * @param {Number} tag
185  * @param {Number} color
186  * @param {Number} opacity
187  * @param {cc.Node} customNode
188  * @returns {ccui.RichElementCustomNode}
189  */
190 ccui.RichElementCustomNode.create = function (tag, color, opacity, customNode) {
191     return new ccui.RichElementCustomNode(tag, color, opacity, customNode);
192 };
193 
194 /**
195  * The rich text control of Cocos UI. It receives text, image, and custom node as its children to display.
196  * @class
197  * @extends ccui.Widget
198  */
199 ccui.RichText = ccui.Widget.extend(/** @lends ccui.RichText# */{
200     _formatTextDirty: false,
201     _richElements: null,
202     _elementRenders: null,
203     _leftSpaceWidth: 0,
204     _verticalSpace: 0,
205     _elementRenderersContainer: null,
206     _lineBreakOnSpace: false,
207     _textHorizontalAlignment: null,
208     _textVerticalAlignment: null,
209 
210     /**
211      * create a rich text
212      * Constructor of ccui.RichText. override it to extend the construction behavior, remember to call "this._super()" in the extended "ctor" function.
213      * @example
214      * var uiRichText = new ccui.RichTex();
215      */
216     ctor: function () {
217         ccui.Widget.prototype.ctor.call(this);
218         this._formatTextDirty = false;
219         this._richElements = [];
220         this._elementRenders = [];
221         this._leftSpaceWidth = 0;
222         this._verticalSpace = 0;
223         this._textHorizontalAlignment = cc.TEXT_ALIGNMENT_LEFT;
224         this._textVerticalAlignment = cc.VERTICAL_TEXT_ALIGNMENT_TOP;
225     },
226 
227     _initRenderer: function () {
228         this._elementRenderersContainer = new cc.Node();
229         this._elementRenderersContainer.setAnchorPoint(0.5, 0.5);
230         this.addProtectedChild(this._elementRenderersContainer, 0, -1);
231     },
232 
233     /**
234      * Insert a element
235      * @param {ccui.RichElement} element
236      * @param {Number} index
237      */
238     insertElement: function (element, index) {
239         this._richElements.splice(index, 0, element);
240         this._formatTextDirty = true;
241     },
242 
243     /**
244      * Push a element
245      * @param {ccui.RichElement} element
246      */
247     pushBackElement: function (element) {
248         this._richElements.push(element);
249         this._formatTextDirty = true;
250     },
251 
252     /**
253      * Remove element
254      * @param {ccui.RichElement} element
255      */
256     removeElement: function (element) {
257         if (cc.isNumber(element))
258             this._richElements.splice(element, 1);
259          else
260             cc.arrayRemoveObject(this._richElements, element);
261         this._formatTextDirty = true;
262     },
263 
264     /**
265      * Formats the richText's content.
266      */
267     formatText: function () {
268         if (this._formatTextDirty) {
269             this._elementRenderersContainer.removeAllChildren();
270             this._elementRenders.length = 0;
271             var i, element, locRichElements = this._richElements;
272             if (this._ignoreSize) {
273                 this._addNewLine();
274                 for (i = 0; i < locRichElements.length; i++) {
275                     element = locRichElements[i];
276                     var elementRenderer = null;
277                     switch (element._type) {
278                         case ccui.RichElement.TEXT:
279                             if( element._fontDefinition)
280                                 elementRenderer = new cc.LabelTTF(element._text, element._fontDefinition);
281                             else //todo: There may be ambiguous
282                                 elementRenderer = new cc.LabelTTF(element._text, element._fontName, element._fontSize);
283                             break;
284                         case ccui.RichElement.IMAGE:
285                             elementRenderer = new cc.Sprite(element._filePath);
286                             break;
287                         case ccui.RichElement.CUSTOM:
288                             elementRenderer = element._customNode;
289                             break;
290                         default:
291                             break;
292                     }
293                     elementRenderer.setColor(element._color);
294                     elementRenderer.setOpacity(element._color.a);
295                     this._pushToContainer(elementRenderer);
296                 }
297             } else {
298                 this._addNewLine();
299                 for (i = 0; i < locRichElements.length; i++) {
300                     element = locRichElements[i];
301                     switch (element._type) {
302                         case ccui.RichElement.TEXT:
303                             if( element._fontDefinition)
304                                 this._handleTextRenderer(element._text, element._fontDefinition, element._fontDefinition.fontSize, element._fontDefinition.fillStyle);
305                             else
306                                 this._handleTextRenderer(element._text, element._fontName, element._fontSize, element._color);
307                             break;
308                         case ccui.RichElement.IMAGE:
309                             this._handleImageRenderer(element._filePath, element._color, element._color.a);
310                             break;
311                         case ccui.RichElement.CUSTOM:
312                             this._handleCustomRenderer(element._customNode);
313                             break;
314                         default:
315                             break;
316                     }
317                 }
318             }
319             this.formatRenderers();
320             this._formatTextDirty = false;
321         }
322     },
323     /**
324      * Prepare the child LabelTTF based on line breaking
325      * @param {String} text
326      * @param {String|cc.FontDefinition} fontNameOrFontDef
327      * @param {Number} fontSize
328      * @param {cc.Color} color
329      * @private
330      */
331     _handleTextRenderer: function (text, fontNameOrFontDef, fontSize, color) {
332         if(text === "")
333             return;
334 
335         if(text === "\n"){ //Force Line Breaking
336             this._addNewLine();
337             return;
338         }
339 
340         var textRenderer = fontNameOrFontDef instanceof cc.FontDefinition ? new cc.LabelTTF(text, fontNameOrFontDef) : new cc.LabelTTF(text, fontNameOrFontDef, fontSize);
341         var textRendererWidth = textRenderer.getContentSize().width;
342         this._leftSpaceWidth -= textRendererWidth;
343         if (this._leftSpaceWidth < 0) {
344             var overstepPercent = (-this._leftSpaceWidth) / textRendererWidth;
345             var curText = text;
346             var stringLength = curText.length;
347             var leftLength = stringLength * (1 - overstepPercent);
348             var leftWords = curText.substr(0, leftLength);
349             var cutWords = curText.substr(leftLength, curText.length - 1);
350             var validLeftLength = leftLength > 0;
351 
352             if(this._lineBreakOnSpace){
353                 var lastSpaceIndex = leftWords.lastIndexOf(' ');
354                 leftLength = lastSpaceIndex === -1 ? leftLength : lastSpaceIndex+1 ;
355                 cutWords = curText.substr(leftLength, curText.length - 1);
356                 validLeftLength = leftLength > 0 && cutWords !== " ";
357             }
358 
359             if (validLeftLength) {
360                 var leftRenderer = null;
361                 if( fontNameOrFontDef instanceof cc.FontDefinition)
362                 {
363                     leftRenderer = new cc.LabelTTF(leftWords.substr(0, leftLength), fontNameOrFontDef);
364                     leftRenderer.setOpacity(fontNameOrFontDef.fillStyle.a); //TODO: Verify that might not be needed...
365                 }else{
366                     leftRenderer =  new cc.LabelTTF(leftWords.substr(0, leftLength), fontNameOrFontDef, fontSize);
367                     leftRenderer.setColor(color);
368                     leftRenderer.setOpacity(color.a);
369                 }
370                 this._pushToContainer(leftRenderer);
371             }
372 
373             this._addNewLine();
374             this._handleTextRenderer(cutWords, fontNameOrFontDef, fontSize, color);
375         } else {
376             if( fontNameOrFontDef instanceof cc.FontDefinition) {
377                 textRenderer.setOpacity(fontNameOrFontDef.fillStyle.a); //TODO: Verify that might not be needed...
378             }else {
379                 textRenderer.setColor(color);
380                 textRenderer.setOpacity(color.a);
381             }
382             this._pushToContainer(textRenderer);
383         }
384     },
385 
386     _handleImageRenderer: function (filePath, color, opacity) {
387         var imageRenderer = new cc.Sprite(filePath);
388         this._handleCustomRenderer(imageRenderer);
389     },
390 
391     _handleCustomRenderer: function (renderer) {
392         var imgSize = renderer.getContentSize();
393         this._leftSpaceWidth -= imgSize.width;
394         if (this._leftSpaceWidth < 0) {
395             this._addNewLine();
396             this._pushToContainer(renderer);
397             this._leftSpaceWidth -= imgSize.width;
398         } else
399             this._pushToContainer(renderer);
400     },
401 
402     _addNewLine: function () {
403         this._leftSpaceWidth = this._customSize.width;
404         this._elementRenders.push([]);
405     },
406 
407     /**
408      * Formats richText's renderer.
409      */
410     formatRenderers: function () {
411         var newContentSizeHeight = 0, locRenderersContainer = this._elementRenderersContainer;
412         var locElementRenders = this._elementRenders;
413         var i, j, row, nextPosX, l;
414         var lineHeight, offsetX;
415         if (this._ignoreSize) {
416             var newContentSizeWidth = 0;
417             row = locElementRenders[0];
418             nextPosX = 0;
419 
420             for (j = 0; j < row.length; j++) {
421                 l = row[j];
422                 l.setAnchorPoint(cc.p(0, 0));
423                 l.setPosition(nextPosX, 0);
424                 locRenderersContainer.addChild(l, 1, j);
425 
426                 lineHeight = l.getLineHeight ? l.getLineHeight() : newContentSizeHeight;
427 
428                 var iSize = l.getContentSize();
429                 newContentSizeWidth += iSize.width;
430                 newContentSizeHeight = Math.max(Math.min(newContentSizeHeight, lineHeight), iSize.height);
431                 nextPosX += iSize.width;
432             }
433 
434             //Text flow horizontal alignment:
435             if(this._textHorizontalAlignment !== cc.TEXT_ALIGNMENT_LEFT) {
436                 offsetX = 0;
437                 if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_RIGHT)
438                     offsetX = this._contentSize.width - nextPosX;
439                 else if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_CENTER)
440                     offsetX = (this._contentSize.width - nextPosX) / 2;
441 
442                 for (j = 0; j < row.length; j++)
443                     row[j].x += offsetX;
444             }
445 
446             locRenderersContainer.setContentSize(newContentSizeWidth, newContentSizeHeight);
447         } else {
448             var maxHeights = [];
449             for (i = 0; i < locElementRenders.length; i++) {
450                 row = locElementRenders[i];
451                 var maxHeight = 0;
452                 for (j = 0; j < row.length; j++) {
453                     l = row[j];
454                     lineHeight = l.getLineHeight ? l.getLineHeight() : l.getContentSize().height;
455                     maxHeight = Math.max(Math.min(l.getContentSize().height, lineHeight), maxHeight);
456                 }
457                 maxHeights[i] = maxHeight;
458                 newContentSizeHeight += maxHeights[i];
459             }
460 
461             var nextPosY = this._customSize.height;
462 
463             for (i = 0; i < locElementRenders.length; i++) {
464                 row = locElementRenders[i];
465                 nextPosX = 0;
466                 nextPosY -= (maxHeights[i] + this._verticalSpace);
467 
468                 for (j = 0; j < row.length; j++) {
469                     l = row[j];
470                     l.setAnchorPoint(cc.p(0, 0));
471                     l.setPosition(cc.p(nextPosX, nextPosY));
472                     locRenderersContainer.addChild(l, 1);
473                     nextPosX += l.getContentSize().width;
474                 }
475                 //Text flow alignment(s)
476                 if( this._textHorizontalAlignment !== cc.TEXT_ALIGNMENT_LEFT || this._textVerticalAlignment !== cc.VERTICAL_TEXT_ALIGNMENT_TOP) {
477                     offsetX = 0;
478                     if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_RIGHT)
479                         offsetX = this._contentSize.width - nextPosX;
480                     else if (this._textHorizontalAlignment === cc.TEXT_ALIGNMENT_CENTER)
481                         offsetX = (this._contentSize.width - nextPosX) / 2;
482 
483                     var offsetY = 0;
484                     if (this._textVerticalAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM)
485                         offsetY = this._customSize.height - newContentSizeHeight;
486                     else if (this._textVerticalAlignment === cc.VERTICAL_TEXT_ALIGNMENT_CENTER)
487                         offsetY = (this._customSize.height - newContentSizeHeight) / 2;
488 
489                     for (j = 0; j < row.length; j++) {
490                         l = row[j];
491                         l.x += offsetX;
492                         l.y -= offsetY;
493                     }
494                 }
495             }
496 
497             locRenderersContainer.setContentSize(this._contentSize);
498         }
499 
500         var length = locElementRenders.length;
501         for (i = 0; i<length; i++){
502             locElementRenders[i].length = 0;
503         }
504         this._elementRenders.length = 0;
505 
506         this.setContentSize(this._ignoreSize?this.getVirtualRendererSize():this._customSize);
507         this._updateContentSizeWithTextureSize(this._contentSize);
508 
509         locRenderersContainer.setPosition(this._contentSize.width * 0.5, this._contentSize.height * 0.5);
510     },
511 
512     _pushToContainer: function (renderer) {
513         if (this._elementRenders.length <= 0)
514             return;
515         this._elementRenders[this._elementRenders.length - 1].push(renderer);
516     },
517 
518     _adaptRenderers: function(){
519         this.formatText();
520     },
521 
522     /**
523      * Sets vertical space
524      * @param {Number} space
525      */
526     setVerticalSpace: function (space) {
527         this._verticalSpace = space;
528     },
529 
530     /**
531      * Sets anchor point
532      * @override
533      * @param {cc.Point} pt
534      */
535     setAnchorPoint: function (pt) {
536         ccui.Widget.prototype.setAnchorPoint.call(this, pt);
537         this._elementRenderersContainer.setAnchorPoint(pt);
538     },
539     _setAnchorX: function (x) {
540         ccui.Widget.prototype._setAnchorX.call(this, x);
541         this._elementRenderersContainer._setAnchorX(x);
542     },
543     _setAnchorY: function (y) {
544         ccui.Widget.prototype._setAnchorY.call(this, y);
545         this._elementRenderersContainer._setAnchorY(y);
546     },
547 
548     /**
549      * Returns the renderer container's content size.
550      * @override
551      * @returns {cc.Size}
552      */
553     getVirtualRendererSize: function(){
554         return this._elementRenderersContainer.getContentSize();
555     },
556 
557     /**
558      * Ignore the richText's custom size, If ignore is true that richText will ignore it's custom size, use renderer's content size, false otherwise.
559      * @param {Boolean} ignore
560      * @override
561      */
562     ignoreContentAdaptWithSize: function (ignore) {
563         if (this._ignoreSize !== ignore) {
564             this._formatTextDirty = true;
565             ccui.Widget.prototype.ignoreContentAdaptWithSize.call(this, ignore);
566         }
567     },
568 
569     /**
570      * Gets the content size of ccui.RichText
571      * @override
572      * @return {cc.Size}
573      */
574     getContentSize: function(){
575         this.formatText();
576         return cc.Node.prototype.getContentSize.call(this);
577     },
578     _getWidth: function() {
579         this.formatText();
580         return cc.Node.prototype._getWidth.call(this);
581     },
582     _getHeight: function() {
583         this.formatText();
584         return cc.Node.prototype._getHeight.call(this);
585     },
586 
587     setContentSize: function(contentSize, height){
588         var locWidth = (height === undefined) ? contentSize.width : contentSize;
589         var locHeight = (height === undefined) ? contentSize.height : height;
590         ccui.Widget.prototype.setContentSize.call(this, locWidth, locHeight);
591         this._formatTextDirty = true;
592     },
593 
594     /**
595      * Returns the class name of ccui.RichText.
596      * @returns {string}
597      */
598     getDescription: function(){
599         return "RichText";
600     },
601     /**
602      * Allow child renderer to be affected by ccui.RichText's opacity
603      * @param {boolean} value
604      */
605     setCascadeOpacityEnabled: function(value) {
606         this._super(value);
607         this._elementRenderersContainer.setCascadeOpacityEnabled(value);
608     },
609     /**
610      * This allow the RichText layout to break line on space only like in Latin text format
611      * by default the property is false, which break the line on characters
612      * @param value
613      */
614     setLineBreakOnSpace: function(value){
615         this._lineBreakOnSpace = value;
616         this._formatTextDirty = true;
617         this.formatText();
618     },
619     /**
620      * Set the renderer horizontal flow alignment for the Control
621      * although it is named TextHorizontalAlignment, it should work with all type of renderer too.
622      * NOTE: we should rename this to setHorizontalAlignment directly
623      *
624      * @example
625      * var richText = new ccui.RichText();
626      * richText.setTextHorizontalAlignment(cc.Text_ALIGNMENT_RIGHT);
627      *
628      * @param {Number} value - example cc.TEXT_ALIGNMENT_RIGHT
629      */
630     setTextHorizontalAlignment: function(value){
631         if(value !== this._textHorizontalAlignment) {
632             this._textHorizontalAlignment = value;
633             this.formatText();
634         }
635     },
636     /**
637      * Set the renderer vertical flow alignment for the Control
638      * although it is named TextVerticalAlignment, it should work with all type of renderer too.
639      *
640      * @example
641      * var richText = new ccui.RichText();
642      * richText.setTextVerticalAlignment(cc.VERTICAL_TEXT_ALIGNMENT_CENTER);
643      *
644      * @param {Number} value - example cc.VERTICAL_TEXT_ALIGNMENT_CENTER
645      */
646     setTextVerticalAlignment: function(value){
647         if(value !== this._textVerticalAlignment) {
648             this._textVerticalAlignment = value;
649             this.formatText();
650         }
651     }
652 });
653 
654 /**
655  * create a rich text
656  * @deprecated since v3.0, please use new ccui.RichText() instead.
657  * @returns {RichText}
658  */
659 ccui.RichText.create = function(){
660     return new ccui.RichText();
661 };
662 
663 // Constants
664 //Rich element type
665 /**
666  * The text type of rich element.
667  * @constant
668  * @type {number}
669  */
670 ccui.RichElement.TEXT = 0;
671 /**
672  * The image type of rich element.
673  * @constant
674  * @type {number}
675  */
676 ccui.RichElement.IMAGE = 1;
677 /**
678  * The custom type of rich element.
679  * @constant
680  * @type {number}
681  */
682 ccui.RichElement.CUSTOM = 2;