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