Comment  1.0.0

Abricos! User Interface Library > Comment > comment.js (source view)
Filters
/*
@version $Id: comment.js 280 2009-12-28 14:23:58Z roosit $
@copyright Copyright (C) 2008 Abricos All rights reserved.
@license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.php
*/

/**
 * @module Comment
 * @namespace Brick.mod.comment
 */

var Component = new Brick.Component();
Component.requires = {
	mod:[{name: 'sys', files: ['data.js']}]
};
Component.entryPoint = function(){
	
	var Dom = YAHOO.util.Dom,
		E = YAHOO.util.Event,
		L = YAHOO.lang;
	
	var NS = this.namespace;
	var __selfCT = this;

	if (!Brick.objectExists('Brick.mod.comment.data')){
		Brick.mod.comment.data = new Brick.util.data.byid.DataSet('comment');
	}
	var DATA = Brick.mod.comment.data;
	var tSetVar = Brick.util.Template.setProperty;
	var tSetVarA = Brick.util.Template.setPropertyArray;
	
	var _T = {};
	var _TId = {};
	
	/**
	 * Конструктор дерева комментариев на странице.
	 * 
	 * @class Builder
	 * @constructor
	 * @param {String} elementId Идентификатор HTML элемента, который содержит 
	 * в себе список комментариев: имя пользователя, идентификатор и текст комментария.
	 * @param {Integer} dbContentId Идентификатор из таблицы контента на сервера. 
	 * @param {Object} data Сопутствующие данные комментариев.
	 */
	var Builder = function(elementId, dbContentId, data){
		this.init(elementId, dbContentId, data);
	};

	/**
	 * Хеш таблица экземпляров Builder.
	 * 
	 * @private
	 * @static
	 * @property _instances
	 * @type Object
	 */
	Builder._instances = {};

	/**
	 * Получить объект Builder по HTML идентификатору.
	 * 
	 * @method getBuilderById
	 * @static
	 * @param {String} Идентификатор HTML элемента.
	 */
	Builder.getBuilderById = function(id) {
        if (Editor._instances[id]) {
            return Editor._instances[id];
        }
        return null;
    };


	Builder.prototype = {
		/**
		 * HTML элемент в котором будет построено дерево комментариев.
		 * 
		 * @property element
		 * @type HTMLElement
		 */
		element: null,
		
		/**
		 * Идентификатор из таблицы контента на сервера.
		 * 
		 * @property dbContentId
		 * @type Integer
		 */
		dbContentId: null,
		
		/**
		 * Идентификатор последнего комментария
		 * 
		 * @property lastCommentId
		 * @type Integer
		 */
		lastCommentId: 0,
		
		/**
		 * Кол-во комментариев.
		 * 
		 * @property count
		 * @type Integer
		 */
		count: 0,
		
		/**
		 * Открытый редактор комментария.
		 * 
		 * @property reply
		 * @type Brick.mod.comment.Reply
		 */
		reply: null,
		
		/**
		 * Инициализация конструктора дерева комментариев.
		 * 
		 * @method init
		 * @param {String} elementId Идентификатор HTML элемента, который содержит 
		 * в себе список начальных данных комментариев: имя пользователя, идентификатор 
		 * и текст комментария.
		 * @param {Integer} dbContentId Идентификатор из таблицы контента на сервера. 
		 * @param {Object} data Сопутствующие данные комментариев.
		 */
		init: function(elementId, dbContentId, data){
			this.dbContentId = dbContentId;
			this.element = Dom.get(elementId);
			if (L.isNull(this.element)){ return; }
			
			Builder._instances[elementId] = this;

			var template = __selfCT.template.get(elementId);
			_T[elementId] = template.data; 
			_TId[elementId] = template.idManager;
			this.build(data);
		},
		
		/**
		 * Построить HTML код комментария из шаблона.
		 * 
		 * @method _getHTMLNode
		 * @private 
		 * @param {Object} di Данные комментария. 
		 */
		_getHTMLNode: function(di){
			var T = _T[this.element.id];
			return tSetVarA(T['comment'], {
				'unm': di['unm'],
				'ttname': Brick.env.ttname,
				'reply': (Brick.env.user.isRegister() ? T['reply'] : ""),
				'de':  Brick.dateExt.convert(di['de']),
				'id': di['id'],
				'bd': di['st']>0?T['spam']: di['bd']
			});
		},
		
		/**
		 * Построить дерево комментариев.
		 * 
		 * @param data
		 * @return
		 */
		build: function(data){
			var el = this.element;
			
			// чтение данных
			var body = {};
			while(el.childNodes.length){
				var t = el.childNodes[0];
				if (t.childNodes.length == 3){
					body[t.childNodes[0].innerHTML] = t.childNodes[2].innerHTML;
				}
				el.removeChild(t);
			}
			var T = _T[el.id];
			var TId = _TId[el.id];
			
			el.innerHTML = tSetVarA(T['panel'], {'id': this.dbContentId, 'ttname': Brick.env.ttname });
			
			var getEl = function(name){ return Dom.get(TId['panel'][name]); };
			
			if (Brick.env.user.isRegister()){
				getEl('replyrootnone').style.display = 'none';
			}else{
				getEl('breplyroot').style.display = 'none';
			}

			var __self = this;
			var lastCommentId = 0;
			var _buildTree = function(container, pid){
				
				var i, di, lst = "";
				for (i=0;i<data.length;i++){
					di = data[i];
					if (di['id']*1 > lastCommentId){
						lastCommentId = di['id']*1;
					}
					if (di['pid'] == pid){
						di['bd'] = body[di['id']];
						lst += __self._getHTMLNode(di);
					}
				}
				if (lst.length == 0){ return; }
				var t = tSetVar(T['list'], 'id', pid);
				container.innerHTML = tSetVar(t, 'list', lst);
				
				for (i=0;i<data.length;i++){
					di = data[i];
					if (di['pid'] == pid){
						var child = Dom.get(TId['comment']['child']+'-'+di['id']);
						_buildTree(child, di['id']);
					}
				}
			};
			
			_buildTree(getEl('list'), 0);

			this.lastCommentId = lastCommentId;
			this.count = data.length;
			this.renderCount();
			
			var __self = this;
			E.on(el, 'click', function(e){if (__self.onClick(E.getTarget(e))){ E.stopEvent(e);}});
			
			var tables = {'comments': DATA.get('comments', true)};
			var rows = tables['comments'].getRows({'cid': this.dbContentId}, {'lid': lastCommentId});
			DATA.onComplete.subscribe(this.dsComplete, this, true);
		},
		
		/**
		 * Обработать событие DataSet.
		 * 
		 * @method dsComplete
		 * @param type
		 * @param args
		 */
		dsComplete: function(type, args){
			if (!args[0].checkWithParam('comments', {'cid': this.dbContentId})){ return; }
			
			var __self = this;
			var T = _T[this.element.id];
			var TId = _TId[this.element.id];
			var rows = DATA.get('comments').getRows({'cid': this.dbContentId});
			var lastid = this.lastCommentId;
			var count = this.count;
			rows.foreach(function(row){
				var di = row.cell;
				var pid = di['pid'];
				if (di['id']*1 > lastid){ lastid = di['id']*1; }
				var item = __self._getHTMLNode(di);
				var child = (count == 0 ? Dom.get(TId['panel']['list']) : Dom.get(TId['comment']['child']+'-'+pid));
				var list = Dom.get(TId['list']['id']+'-'+pid);
				if (L.isNull(list)){
					var t = tSetVar(T['list'], 'id', pid);
					child.innerHTML = tSetVar(t, 'list', item);
				}else{
					list.innerHTML += item;
				}
				count++;
			});
			
			this.count = count;
			this.lastCommentId = lastid;
			rows.overparam.lid = lastid;
			this.renderCount();
		},
		
		/**
		 * Перерисовать кол-во комментариев
		 * 
		 * @method renderCount
		 */
		renderCount: function(){
			var TId = _TId[this.element.id];
			var span = Dom.get(TId['panel']['count']);
			span.innerHTML = "("+this.count+")";
		},
		
		/**
		 * Обработать клик мыши.
		 * 
		 * @method onClick
		 * @param {HTMLElement} el
		 * @return {Boolean}
		 */
		onClick: function(el){
			if (!L.isNull(this.reply)){
				if (this.reply.onClick(el)){ return true; }
			}
			var TId = _TId[this.element.id];
			var tp = TId['panel'];
			switch(el.id){
			case tp['breplyroot']:
				this.showReply(0);
				return true;
			case tp['refresh']:
			case tp['refreshimg']:
				this.refresh();
				return true;
			}
			
			var prefix = el.id.replace(/([0-9]+$)/, '');
			var numid = el.id.replace(prefix, "");
			
			if (prefix == TId['reply']['id']+'-'){
				this.showReply(numid); return true;
			}
			return false;
		},
		
		/**
		 * Написать комментарий.
		 * 
		 * @method showReply
		 * @param {Integer} parentCommentId Идентификатор комментария.
		 */
		showReply: function(parentCommentId){
			if (!L.isNull(this.reply)){
				this.reply.destroy();
			}
			this.reply = new Reply(this, parentCommentId);
		},
		
		/**
		 * Запросить сервер обновить дерево комментариев, а именно, 
		 * подгрузить новые комментарии, если таковые имеются.
		 * 
		 * @method refresh
		 */
		refresh: function(){
			var table = DATA.get('comments');
			var rows = table.getRows({'cid': this.dbContentId});
			rows.clear();
			DATA.request();
		}
	};
	
	Brick.mod.comment.Builder = Builder;	

	
	/**
	 * Виджет "Написать комментарий"
	 * 
	 * @class Reply
	 * @constructor
	 * @param {Brick.mod.comment.Builder} owner Конструктор дерева комментариев.
	 * @param {Integer} parentCommentId Идентификатор комментария родителя, в таблице 
	 * комментариев на сервера, на который будет дан ответ, если 0, то это будет 
	 * первый комментарий.  
	 */
	var Reply = function(owner, parentCommentId){
		parentCommentId = parentCommentId*1 || 0;
		this.init(owner, parentCommentId);
	};

	Reply.prototype = {
		
		/**
		 * Конструктор дерева комментариев.
		 * 
		 * @property owner
		 * @type Brick.mod.comment.Builder
		 */
		owner: null,
		
		/**
		 * Идентификатор комментария родителя, в таблице 
		 * комментариев на сервера, на который будет дан ответ, если 0, то это будет 
		 * первый комментарий.
		 * 
		 * @property parentCommentId
		 * @type Integer
		 */
		parentCommentId: 0,
		
		/**
		 * Шаблон компонента.
		 * 
		 * @property _T
		 * @private
		 * @type Object
		 */
		_T: null,

		/**
		 * Мененджер идентификаторов HTML элеменов из шаблона.
		 * 
		 * @property _TId
		 * @private
		 * @type Object
		 */
		_TId: null,
		
		/**
		 * Редактор комментария.
		 * 
		 * @property editor
		 * @type Brick.widget.Editor
		 */
		editor: null,
		
		/**
		 * Инициализировать редактор.
		 * 
		 * @method init
		 * @param {Brick.mod.comment.Builder} owner Конструктор дерева комментариев.
		 * @param {Integer} parentCommentId Идентификатор комментария родителя.
		 */
		init: function(owner, parentCommentId){
			this.owner = owner;
			this.parentCommentId = parentCommentId;
			
			var T = this._T = _T[this.owner.element.id];
			var TId = this._TId = _TId[this.owner.element.id];
			
			if (parentCommentId == 0){
				this.contbutton = Dom.get(TId['panel']['replycont']);
				this.panel = Dom.get(TId['panel']['reply']);
			}else{
				this.contbutton = Dom.get(TId['reply']['contbtn']+'-'+parentCommentId);
				this.panel = Dom.get(TId['reply']['reply']+'-'+parentCommentId);
			}
			this.contbutton.style.display = 'none';
			
			var __self = this;
			this.panel.innerHTML = T['replypanel'];
			Brick.Component.API.fireFunction('sys', 'editor', function(){
				var Editor = Brick.widget.Editor;
				__self.editor = new Editor(TId['replypanel']['editor'], {
					'mode': Editor.MODE_VISUAL,
					'toolbar': Editor.TOOLBAR_MINIMAL
				});
			});
		},
		
		/**
		 * Закрыть и разрушить панель.
		 * 
		 * @method destroy
		 */
		destroy: function(){
			this.editor.destroy();
			this.contbutton.style.display = "";
			Brick.elClear(this.panel);
			this.owner.reply = null;
		},
		
		/**
		 * Просмотреть комментарий как он будет выглядеть после отправки.
		 * 
		 * @method preview
		 */
		preview: function(){
			var table = DATA.get('preview', true);
			table.columns.update(["id","bd"]);
			var row = table.newRow();
			row.cell['bd'] = this.editor.getContent();
			var rows = table.getRows();
			rows.clear();
			rows.add(row);
			table.applyChanges();
			var TId = this._TId;
			var oncomplete = function(){
				Dom.get(TId['replypanel']['preview']).innerHTML = rows.getById(1).cell['bd'];
				DATA.onComplete.unsubscribe(oncomplete);
			};
			DATA.onComplete.subscribe(oncomplete);
			DATA.request();
		},
		
		/**
		 * Отправить комментарий.
		 * 
		 * @method send
		 */
		send: function(){
			var table = DATA.get('comments');
			var rows = table.getRows({'cid': this.owner.dbContentId});
			var row = table.newRow();
			row.cell['pid'] = this.parentCommentId;
			row.cell['bd'] = this.editor.getContent();
			rows.add(row);
			table.applyChanges();
			DATA.request();
			this.destroy();
		},
		
		/**
		 * Обработать клик мыши.
		 * 
		 * @method onClick
		 * @param {HTMLElement} el
		 * @return {Boolean}
		 */
		onClick: function(el){
			var tp = this._TId['replypanel'];
			switch(el.id){
			case tp['bcancel']: this.destroy(); return true;
			case tp['bsend']: this.send();	return true;
			case tp['bpreview']: this.preview(); return true;
			}
			return false;
		}
	};
	
	Brick.mod.comment.Reply = Reply;
	
};