Source: chemdoc/kekule.contentBlocks.js

/**
 * @fileoverview
 * Implementation of text/rich text block in 2D drawing.
 * @author Partridge Jiang
 */

/*
 * requires /lan/classes.js
 * requires /core/kekule.common.js
 */

(function(){
"use strict";

var CM = Kekule.CoordMode;
var CU = Kekule.CoordUtils;

/**
 * Represent an block of content in chem document (especially in 2D rendering,drawing in rect),
 * like text block or image.
 * @class
 * @augments Kekule.ChemObject
 * @param {String} id Id of this block.
 * @param {Hash} coord2D The top left 2D coordinates of block, {x, y}, can be null.
 * @param {Hash} coord3D The min 3D coordinates of block box, {x, y, z}, can be null. Usually unneeded.
 *
 * @property {Hash} coord2D The 2D coordinates of glyph, {x, y}.
 * @property {Hash} coord3D The 3D coordinates of glyph, {x, y, z}.
 * @property {Hash} absCoord2D The absolute 2D coordinates of glyph, {x, y}.
 * @property {Hash} absCoord3D The absolute 3D coordinates of glyph, {x, y, z}.
 * @property {Hash} size2D The 2D dimension (width, height) of glyph, {x, y}.
 * @property {Hash} size3D The 3D dimension (width, height, depth) of glyph, {x, y, z}.
 *
 * @borrows Kekule.ClassDefineUtils.CommonCoordMethods#getCoordOfMode as #getCoordOfMode
 * @borrows Kekule.ClassDefineUtils.CommonCoordMethods#setCoordOfMode as #setCoordOfMode
 * @borrows Kekule.ClassDefineUtils.Coord2DMethods#fetchCoord2D as #fetchCoord2D
 * @borrows Kekule.ClassDefineUtils.Coord2DMethods#hasCoord2D as #hasCoord2D
 * @borrows Kekule.ClassDefineUtils.Coord2DMethods#get2DX as #get2DX
 * @borrows Kekule.ClassDefineUtils.Coord2DMethods#set2DX as #set2DX
 * @borrows Kekule.ClassDefineUtils.Coord2DMethods#get2DY as #get2DY
 * @borrows Kekule.ClassDefineUtils.Coord2DMethods#set2DY as #set2DY
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#fetchCoord3D as #fetchCoord3D
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#hasCoord2D as #hasCoord3D
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#get3DX as #get3DX
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#set3DX as #set3DX
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#get3DY as #get3DY
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#set3DY as #set3DY
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#get3DZ as #get3DZ
 * @borrows Kekule.ClassDefineUtils.Coord3DMethods#set3DZ as #set3DZ
 * @borrows Kekule.ClassDefineUtils.CommonSizeMethods#getSizeOfMode as #getSizeOfMode
 * @borrows Kekule.ClassDefineUtils.CommonSizeMethods#setSizeOfMode as #setSizeOfMode
 * @borrows Kekule.ClassDefineUtils.CommonSizeMethods#getBoxOfMode as #getBoxOfMode
 * @borrows Kekule.ClassDefineUtils.Size2DMethods#fetchSize2D as #fetchSize2D
 * @borrows Kekule.ClassDefineUtils.Size2DMethods#hasSize2D as #hasSize2D
 * @borrows Kekule.ClassDefineUtils.Size2DMethods#get2DSizeX as #get2DSizeX
 * @borrows Kekule.ClassDefineUtils.Size2DMethods#set2DSizeX as #set2DSizeX
 * @borrows Kekule.ClassDefineUtils.Size2DMethods#get2DSizeY as #get2DSizeY
 * @borrows Kekule.ClassDefineUtils.Size2DMethods#set2DSizeY as #set2DSizeY
 * @borrows Kekule.ClassDefineUtils.CommonSizeMethods#getBox2D as #getBox2D
 * @borrows Kekule.ClassDefineUtils.Size3DMethods#fetchSize3D as #fetchSize3D
 * @borrows Kekule.ClassDefineUtils.Size3DMethods#hasSize3D as #hasSize3D
 * @borrows Kekule.ClassDefineUtils.Size3DMethods#get3DSizeX as #get3DSizeX
 * @borrows Kekule.ClassDefineUtils.Size3DMethods#set3DSizeX as #set3DSizeX
 * @borrows Kekule.ClassDefineUtils.Size3DMethods#get3DSizeY as #get3DSizeY
 * @borrows Kekule.ClassDefineUtils.Size3DMethods#set3DSizeY as #set3DSizeY
 * @borrows Kekule.ClassDefineUtils.CommonSizeMethods#getBox3D as #getBox3D
 */
Kekule.ContentBlock = Class.create(Kekule.ChemObject,
/** @lends Kekule.ContentBlock# */
{
	/** @private */
	CLASS_NAME: 'Kekule.ContentBlock',
	/**
	 * @constructs
	 */
	initialize: function($super, id, coord2D, coord3D)
	{
		$super(id);
		if (coord2D)
			this.setCoord2D(coord2D);
		if (coord3D)
			this.setCoord3D(coord3D);
	},
	/** @private */
	initProperties: function()
	{
		// special property, indicate whether the block has been changed and
		// the size should be recalculated
		this.defineProp('needRecalcSize', {'dataType': DataType.BOOL});
	},
	/** @private */
	getAutoIdPrefix: function()
	{
		return 'b';
	},
	/**
	 * Returns coord of top-left corner of block.
	 * @param {Int} coordMode
	 * @param {Bool} allowCoordBorrow
	 * @returns {Object}
	 */
	getCornerCoord1: function(coordMode, allowCoordBorrow)
	{
		return this.getCoordOfMode(coordMode, allowCoordBorrow);
	},
	/*
	 * Set coord of top-left corner of block.
	 * @param {Hash} value
	 * @param {Int} coordMode
	 */
	/*
	setCornerCoord1: function(value, coordMode)
	{
		this.setCoordOfMode(value, coordMode);
		return this;
	},
	*/
	/**
	 * Returns coord of bottom-right corner of block.
	 * @param {Int} coordMode
	 * @param {Bool} allowCoordBorrow
	 * @returns {Object}
	 */
	getCornerCoord2: function(coordMode, allowCoordBorrow)
	{
		var cornerCoord1 = this.getCornerCoord1(coordMode, allowCoordBorrow);
		var size = this.getSizeOfMode(coordMode, allowCoordBorrow);
		return Kekule.CoordUtils.add(cornerCoord1, size);
	},
	/*
	 * Set coord of bottom corner of block.
	 * @param {Hash} value
	 * @param {Int} coordMode
	 */
	/*
	setCornerCoord2: function(value, coordMode)
	{
		var cornerCoord1 = this.getCornerCoord1(coordMode, allowCoordBorrow);
		var delta = Kekule.CoordUtils.substract(value, cornerCoord1);
		this.setSizeOfMode(delta, coordMode);
		return this;
	},
	*/
	/**
	 * Calculate the box to fit the image on context.
	 * @param {Int} coordMode Determine to calculate 2D or 3D box. Value from {@link Kekule.CoordMode}.
	 * @param {Bool} allowCoordBorrow
	 * @returns {Hash} Box information. {x1, y1, z1, x2, y2, z2} (in 2D mode z1 and z2 will not be set).
	 */
	getContainerBox: function($super, coordMode, allowCoordBorrow)
	{
		var coord1 = this.getAbsCoordOfMode(coordMode, allowCoordBorrow) || {};
		var size = this.getSizeOfMode(coordMode, allowCoordBorrow) || {};
		if (coordMode === Kekule.CoordMode.COORD3D)
			var coord2 = Kekule.CoordUtils.add(coord1, this.getSizeOfMode(coordMode, allowCoordBorrow) || {});
		else // 2D
		{
			coord2 = {
				x: coord1.x + size.x,
				y: coord1.y - size.y
			};
		}
		/*
		var result = {'x1': coord1.x, 'y1': coord1.y, 'x2': coord2.x, 'y2': coord2.y};
		if (coordMode === Kekule.CoordMode.COORD3D)
		{
			result.z1 = coord1.z;
			result.z2 = coord2.z;
		}
		*/
		var result = Kekule.BoxUtils.createBox(coord1, coord2);
		return result;
	}
});
Kekule.ClassDefineUtils.addStandardCoordSupport(Kekule.ContentBlock);
Kekule.ClassDefineUtils.addStandardSizeSupport(Kekule.ContentBlock);

/**
 * Represent an block of pure text in chem document (especially in 2D rendering).
 * @class
 * @augments Kekule.ContentBlock
 * @param {String} id Id of this node.
 * @param {String} text Texts in block, "\n" is allowed.
 * @param {Hash} coord2D The top left 2D coordinates of text block, {x, y}, can be null.
 * @param {Hash} coord3D The min 3D coordinates of text block box, {x, y, z}, can be null. Usually unneeded.
 *
 * @property {String} text Texts in block, "\n" is allowed.
 */
Kekule.TextBlock = Class.create(Kekule.ContentBlock,
/** @lends Kekule.TextBlock# */
{
	/** @private */
	CLASS_NAME: 'Kekule.TextBlock',
	/**
	 * @constructs
	 */
	initialize: function($super, id, text, coord2D, coord3D)
	{
		$super(id, coord2D, coord3D);
		this.setText(text || '');
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('text', {'dataType': DataType.STRING});
	},
	/** @private */
	getAutoIdPrefix: function()
	{
		return 't';
	},
	/** @ignore */
	doObjectChange: function($super, modifiedPropNames)
	{
		// when text block changed, size may need to be recalculated
		if (Kekule.ArrayUtils.intersect(['text', 'renderOptions'], modifiedPropNames).length)
			this.setNeedRecalcSize(true);
	}
});

/**
 * A image block in chem document.
 * @class
 * @augments Kekule.ContentBlock
 * @param {String} id Id of this node.
 * @param {String} src Src url of image.
 * @param {Object} coord2D The 2D coordinates of image top-left, {x, y}, can be null.
 * @param {Object} coord3D The 3D coordinates of image top-left, {x, y, z}, can be null.
 *
 * @property {String} src Src url of image.
 * @property {Hash} size2D Size of image, {x, y}.
 */
Kekule.ImageBlock = Class.create(Kekule.ContentBlock,
/** @lends Kekule.ImageBlock# */
{
	/** @private */
	CLASS_NAME: 'Kekule.ImageBlock',
	/**
	 * @constructs
	 */
	initialize: function($super, id, src, coord2D, coord3D)
	{
		$super(id, coord2D, coord3D);
		if (src)
			this.setSrc(src);
	},
	/** @private */
	initProperties: function()
	{
		this.defineProp('src', {
			'dataType': DataType.STRING,
			'scope': Class.PropertyScope.PUBLISHED,
			'setter': function(value)
			{
				if (value !== this.getSrc())
				{
					this.setPropStoreFieldValue('src', value);
					this._clearCacheImg();
				}
			}
		});
		this.defineProp('cacheImg', {
			'dataType': DataType.OBJECT,
			'scope': Class.PropertyScope.PUBLIC,
			'serializable': false,
			'setter': null,
			'getter': function()
			{
				var result = this.getPropStoreFieldValue('cacheImg');
				if (!result && Kekule.$document)
				{
					result = this._createCacheImg(this.getSrc());
				}
				return result;
			}
		});
	},
	/** @private */
	getAutoIdPrefix: function()
	{
		return 'g';
	},
	/** @private */
	_createCacheImg: function(src)
	{
		var result;
		var doc = Kekule.$document;
		if (doc && doc.body && doc.createElement)
		{
			result = doc.createElement('img');
			result.src = src;
		}
		return result;
	},
	_clearCacheImg: function()
	{
		var img = this.getPropStoreFieldValue('cacheImg');
		if (img)
		{
			img.src = '';
			try
			{
				// clear img prev width/height
				delete img.width;
				delete img.height;
			}
			catch(e)
			{

			}
		}
	}
});

})();