﻿/// <reference name="MicrosoftAjax.js"/>
/// <reference path="Libs/jquery-vsdoc.js" />

function CommentsBuilder(target)
{
    this.maxCommentDepth = 4;
    this.targetContainer = target;
    this.commentContainerId = '';

    this.init();
}
CommentsBuilder.prototype =
{
	commentContainerTemplate: '<div class="comments"><ul class="PlaceForChildComments" commentid="0" id="{0}"></ul></div>',
	refreshTemplate: '<a href="#" class="refresh-comments">Обновить комментарии</a><div class="refresh-comments-preloader"></div>',
	replyButtonTemplate: '<p><a class="ReplyLink ForumReplyLink">Ответить</a></p>',
	commentLinkTemplate: '<span class="s-icon url-icon baloonContainer" style="cursor:pointer;margin-bottom:4px;" objectId="{ObjectId}" commentId="{CommentId}" objectType="{ObjectType}"></span>&nbsp;',
	abuseIconTemplate: '<span class="s-icon abuse-icon baloonContainer" style="cursor:pointer;" objectId="{ObjectId}" commentId="{CommentId}" objectType="{ObjectType}"><i class="b-icon"><i></i></i></span>',
	deletedCommentTemplate: 'Комментарий удален по причине: {ReasonText}. <span class="ShowDeletedComment baloonContainer" commentId="{CommentId}">Что написал?</span>',

	replyFromTemplate: '<span class="replyFrom">как&nbsp;</span>\
        <select class="replyFromList">{0}</select>',


	replyTemplate: '<textarea class="commentTextbox" cols="20" rows="2"></textarea>\
        <div class="CommentReplyTextareaCounter"></div>\
        <a class="commentSubmit" href="#">Отправить</a>\
        <span class="hint zames">или нажмите Ctrl+Enter</span>\
        <span class="reply-from-container">{0}</span>\
        <span>{1}</span>',

	mainReplyTemplate: '<div class="addComment comment-info" style="background-color:transparent;" commentId="{CommentId}" objectId="{ObjectId}" objectType="{ObjectType}">\
            <h3><span class="write-newComment" id="CommentsWndWriteNewRootComment">Написать новый ответ</span></h3>\
            <div class="b-write-newComment">\
                {ReplyTemplate}\
            </div>\
        </div>',

	commentTemplate: '<li commentId="{CommentId}">\
            <a name="comment{CommentId}"></a>\
            <div class="comment-content {IsNewCss} comment-info" commentId="{CommentId}" objectId="{ObjectId}" objectType="{ObjectType}" objectCreatorId="{ObjectCreatorId}">\
                <h6>\
                    {UserNameLink}\
                    &nbsp;<sup class="сomment-type {typeCss}" typeId="{Type}">{TypeText}</sup>\
                    <span class="date">{DateString}</span>\
                </h6>\
                <p class="rating {RatingCss}" objid="{CommentId}" objtype="6">\
		            <a href="#" class="minus">&minus;</a>\
		            <a href="#" class="plus">+</a>\
		            <span class="value">{Rating}</span>\
		            <input type="hidden" class="commentId" value="{CommentId}" />\
	            </p>\
                <p class="icons">\
                    {CommentLinkTemplate}\
                    {AbuseIconTemplate}\
                </p>\
                <div class="Text {delComment}">{Text}</div>\
                {ReplyButtonTemplate}\
                <div class="addComment replyComment"></div>\
            </div>\
            <ul id="ChildComments{CommentId}" commentId="{CommentId}" class="PlaceForChildComments">{subComments}</ul>\
        </li>',

	userNameTemplate: '<a class="userName user-menu-link {IsOnlineCss}" href="{CreatorProfileLink}" title="{IsOnlineText}" usermenu="{ID: {CreatorId}, size: \'medium\'}"><img src="{AvatarURL}" class="avatar" /><span>{Login}</span></a>',
	anonymUserNameTemplate: '<img src="{AvatarURL}" class="avatar" /><span class="userName {IsOnlineCss}" title="{IsOnlineText}">{Login}</span>',

	roles: [{ value: 0, type: 'Spectator', name: 'Зритель', selected: true },
		{ value: 1, type: 'Task', name: 'Автор задания', selected: true },
		{ value: 2, type: 'Solution', name: 'Автор решения', selected: true },
		{ value: 3, type: 'Judge', name: 'Судья' },
		{ value: 4, type: 'Moderator', name: 'Модератор' },
		{ value: 5, type: 'Investor', name: 'Инвестор', selected: true}],

	init: function ()
	{

	},

	Render: function (comments, context)
	{
		var me = this;

		// кнопка "Обновить комментарии"
		if (context.ObjectType != 'Wall')
			this.targetContainer.append(this.refreshTemplate);

		// контейнер комментариев
		this.commentContainerId = String.format('{0}{1}CommentsContainer', context.objectType, context.objectId);
		this.targetContainer.append(this.GetCommentContainerHTML(this.commentContainerId));
		this.GetCommentsContainer()
			.attr('types', context.CommentType)
			.attr('objectType', context.ObjectType)
			.attr('objectCreatorId', context.ObjectCreatorId);

		// рендерим комментарии рекурсивно
		var commentsHtml = [];
		var fc = this._getSubComments(0, comments);
		$.each(fc, function (i, c)
		{
			var t = me.RenderComment(c, comments);
			commentsHtml.push(t);
		});

		// кнопка "Обновить комментарии"
		if (comments.length > 0 && context.ObjectType != 'Wall')
		{
			this.targetContainer.append(this.refreshTemplate);
		}

		// форма "Ответить"
		this.targetContainer.append(this.GetMainReplyHTML(context.ObjectId, context.ObjectType));

		// вставляем html комментариев
		this.GetCommentsContainer().find('ul.PlaceForChildComments').append(commentsHtml.join(''));

		// визивиг
		this.AppendWysiwyg(this.targetContainer, false, context.OnEsc);
	},

	RenderComment: function (comment, comments)
	{
		var me = this;
		// тип комментария
		var typeCss = '';
		switch (comment.Type)
		{
			case 0: typeCss = ''; break;
			case 1: typeCss = 'task'; break;
			case 2: typeCss = 'solution'; break;
			case 3: typeCss = 'moderator'; break;
			case 4: typeCss = 'moderator'; break;
			case 5: typeCss = 'task'; break;
		}

		// комментарий удалён
		if (comment.IsDeleted)
		{
			comment.Text = this.GetDeletedCommentHTML(comment);
		}

		// рендерим дочерние комментарии рекурсивно
		var subCommentsHtml = [];
		var fc = this._getSubComments(comment.Id, comments);
		$.each(fc, function (i, c)
		{
			subCommentsHtml.push(me.RenderComment(c, comments));
		});


		// получаем html
		var RatingCss = 'rated';

		if (!comment.ShowRating)
			RatingCss = 'hidden';
		else if (comment.CanRate == 1)
			RatingCss = '';

		var commenthtml = this.commentTemplate.template({
			CommentId: comment.Id,
			RatingCss: RatingCss,
			delComment: (comment.IsDeleted && comment.IsNew == 0) ? 'delComment' : '',
			typeCss: typeCss,
			IsNewCss: comment.IsNew == 1 ? 'new' : '',
			ReplyButtonTemplate: comment.ShowReply ? this.replyButtonTemplate : '',
			AbuseIconTemplate: comment.IsDeleted ? '' : this.GetAbuseIconHTML(comment),
			CommentLinkTemplate: comment.ShowLink ? this.GetCommentLinkIconHTML(comment) : '',
			ObjectId: comment.ObjectId,
			ObjectType: comment.ObjectType,
			ObjectCreatorId: comment.ObjectCreatorId,
			CreatorId: comment.CreatorId,
			Type: comment.Type,
			TypeText: (comment.Type > 0) ? comment.TypeText : '',
			DateString: comment.DateString,
			Rating: comment.IsDeleted ? '' : comment.Rating,
			Text: comment.Text,
			subComments: subCommentsHtml.join(''),
			UserNameLink: comment.AuthorIsAnonym && comment.ObjectType != 10 ?
                this.anonymUserNameTemplate.template({
                	AvatarURL: comment.AvatarURL,
                	Login: comment.Login,
                	IsOnlineCss: comment.IsOnline ? 'online' : '',
                	IsOnlineText: comment.IsOnline ? 'На сайте' : ''
                }) :
                this.userNameTemplate.template({
                	IsOnlineCss: comment.IsOnline ? 'online' : '',
                	CreatorProfileLink: comment.CreatorProfileLink,
                	IsOnlineText: comment.IsOnline ? 'На сайте' : '',
                	CreatorId: comment.CreatorId,
                	AvatarURL: comment.AvatarURL,
                	Login: comment.Login
                })
		});
		return commenthtml;
	},

	AppendComment: function (comment, toTop)
	{
		if (toTop === undefined)
			toTop = false;

		var commentHtml = this.RenderComment(comment, []);
		var parent = this.GetCommentsContainer().find(String.format('ul.PlaceForChildComments[commentid={0}]', comment.ParentMessageId));
		if (toTop)
			parent.prepend(commentHtml);
		else
			parent.append(commentHtml);
	},

	_getSubComments: function (parentId, comments)
	{
		var filtered = [];

		$.each(comments, function (i, c)
		{
			if (typeof (c) !== 'undefined' && c.ParentMessageId == parentId)
			{
				// удаляем элемент из массива для последующего ускорения поиска
				filtered.push(c);
			}
		});

		return filtered;
	},

	GetCurrentDepth: function (node) { return node.parents('ul.PlaceForChildComments').length; },
	PurgeComment: function (commentId) { $(String.format('li[commentId={0}]', commentId), $(this.targetContainer)).remove(); },
	DeleteComment: function (commentId, reasonText)
	{
		var commentContainer = $(String.format('div.comment-content[commentId={0}]', commentId));
		$('div.Text', commentContainer).html(this.GetDeletedCommentHTML({ ReasonText: reasonText, Id: commentId })).addClass('delComment');
		$('div.replyComment', commentContainer).remove();
		$('a.ReplyLink', commentContainer).parent().remove();
		$('span.abuse-icon', commentContainer).remove();
		$('span.url-icon', commentContainer).remove();
		$('p.rating', commentContainer).remove(); //.addClass('rated');
	},
	GetCommentContainerHTML: function (listId)
	{
		return String.format(this.commentContainerTemplate, listId);
	},

	GetReplyHTML: function ()
	{
		return String.format(this.replyTemplate, this.GetReplyFromHTML(), this.GetReplyAsSolutionHtml());
	},

	GetReplyFromHTML: function ()
	{
		var me = this;
		// роли автора
		var types = this._parseTypes(this.GetCommentsContainer().attr('types'));

		if ((types.length == 1 && types[0] == 0) || !userGate.IsLoggedUser())
		{
			return '';
		}
		else
		{
			var html = [];

			// формируем список ролей
			$.each(this.roles, function (i, r)
			{
				if ($.inArray(r.value, types) > -1)
				{
					// выбрать значение по умолчанию
					var selected = '';
					if (r.selected)
						selected = 'selected="selected"';

					html.push(String.format('<option value="{0}" type="{1}" {3}>{2}</option>', r.value, r.type, r.name, selected));
				}
			});

			return String.format(this.replyFromTemplate, html.join(''));
		}
	},

	GetReplyAsSolutionHtml: function ()
	{
		if (typeof (canAddSolutionToTextTask) == 'undefined' || canAddSolutionToTextTask != 'True')
			return '';

		return '<input class="asSolution" type="checkbox" /><label> как решение к этому заданию</label>';
	},

	_getRole: function (value)
	{
		for (var i = 0; i < this.roles.length; i++)
		{
			var r = this.roles[i];
			if (r.value == value)
				return r;
		}
	},

	_parseTypes: function (types)
	{
		var ts = [];

		if (types == '')
			return ts;

		$.each(types.split(','), function (i, t)
		{
			ts.push(parseInt(t));
		});

		return ts;
	},

	GetMainReplyHTML: function (targetObjectId, targetObjectType)
	{
		return this.mainReplyTemplate.template({
			ReplyTemplate: this.GetReplyHTML(),
			CommentId: 0,
			ObjectId: targetObjectId,
			ObjectType: targetObjectType
		});
	},

	GetDeletedCommentHTML: function (comment)
	{
		return this.deletedCommentTemplate
			.template({ ReasonText: comment.ReasonText, CommentId: comment.Id });
	},

	GetCommentLinkIconHTML: function (comment)
	{
		return this.commentLinkTemplate.template({ ObjectId: comment.ObjectId, CommentId: comment.Id, ObjectType: comment.ObjectType });
	},

	GetAbuseIconHTML: function (comment)
	{
		return this.abuseIconTemplate.template({ ObjectId: comment.ObjectId, CommentId: comment.Id, ObjectType: comment.ObjectType == 90 ? "Wall" : "Comment" });
	},

	AppendReplyContainer: function (target, setFocus, onEsc)
	{
		$('div.replyComment', target).append(this.GetReplyHTML());
		this.AppendWysiwyg(target, setFocus, onEsc);
	},
	RemoveReplyContainer: function (target) { $('div.replyComment', target).remove(); },
	GetCommentContainer: function (target) { return $(target).closest('div.comment-info'); },
	GetCommentContainerByComment: function (comment) { return $(String.format('div.comment-content[commentId={0}]', comment.Id), $(this.targetContainer)); },
	GetCommentReplyContainer: function (target) { return $('a.commentSubmit', target); },
	GetCommentsContainer: function ()
	{
		return this.targetContainer.find('div.comments');
	},
	GetCommentTextContainer: function () { return $('textarea.commentTextbox', $(this.targetContainer)) },
	GetReplyContainer: function () { return $('div.replyComment:visible', $(this.targetContainer)); },
	GetReplyButtonContainer: function () { return $('a.ReplyLink:hidden', $(this.targetContainer)); },
	GetReplyFromListContainer: function (target) { return $('select.replyFromList', target); },
	GetReplyFromContainer: function (target) { return $(target).closest('span.reply-from-container'); },
	GetCommentTypeContainer: function (target) { return $('select.replyFromList option:selected', target); },
	AppendWysiwyg: function (target, setFocus, onEsc)
	{
		var me = this;
		$('textarea.commentTextbox', $(target)).wysiwyg({
			returnCallback: function (e)
			{
				me.GetCommentReplyContainer($(target)).click();
			},
			escCallback: function (e) { onEsc(e); },
			charLimit: 4000,
			autoFocus: setFocus
		});
	},
	destruct: function () { }
};
﻿/// <reference name="MicrosoftAjax.js"/>
/// <reference path="Libs/jquery-vsdoc.js" />
/// <reference path="../WebServices/ForumService.asmx" />
/// <reference path="../WebServices/CommentsService.asmx" />
/// <reference path="CommentsBuilder.js" />

function CommentsManager(container, scrollableContainer)
{
    this._scrollableContainer = scrollableContainer;
    this._container = container;
    this._currentObjectId = null;
    this._commentsCount = 50;
    this._currentObjectType = null;
    this._currentObjectCreatorId = null;
    this._currentCommentType = null;
    this._waitingForServer = false;
    this.init();
}

CommentsManager.prototype =
{
	init: function ()
	{
		this._body = $('html:not(:animated)' + (!$.browser.opera ? ',body:not(:animated)' : ''));
		this._commentsBuilder = new CommentsBuilder(this._container);
		this._commentLinkBaloon = new ObjectLinkBaloon('.url-icon',
            this._container,
            'objectLinkBaloonFrame',
            Function.createDelegate(this, this.GetLinkToComment),
            'commonCommentBaloonContent');
		this._abuseBaloon = new AbuseBaloon('.abuse-icon',
            this._container,
            'abuseBaloonFrame',
            'abuseBaloonContent',
            Function.createDelegate(this, this.OnDeleteComment_Callback),
            Function.createDelegate(this, this.OnPurgeComment_Callback)
        );
		this._deletedCommentBaloon = new SimpleBaloon('span.ShowDeletedComment',
            this._container,
            'objectLinkBaloonFrame',
            $.proxy(this.OnShowDeletedComment_Callback, this),
            'deletedCommentBaloonBaloonContent');
		$('a.ReplyLink', this._container).live('click', $.proxy(this.ShowReplyForm, this));
		$('a.commentSubmit', this._container).live('click', $.proxy(this.OnReplyClick, this));
		$('a.refresh-comments', this._container).live('click', $.proxy(this.Refresh, this));
	},
	OnShowDeletedComment_Callback: function (e)
	{
		//YouDo.Preloader.AppendTo($('div#deletedCommentBaloonBaloonContent'), 32);
		var commentId = $(e.target).attr('commentId');
		YouDo.WebServices.CommentsService.GetCommentTextById(commentId, function (data) { $('div#deletedCommentBaloonBaloonContent').html(data); });
	},
	OnDeleteComment_Callback: function (result)
	{
		if (result[0].toLowerCase() == 'true')
		{
			this._commentsBuilder.DeleteComment(result[1], result[4]);
		}
	},
	OnPurgeComment_Callback: function (result)
	{
		if (result[0].toLowerCase() == 'true')
		{
			this._commentsBuilder.PurgeComment(result[1]);
		}
	},
	GetLinkToComment: function (e, sender)
	{
		var objectType = sender.attr('objectType');
		var virtualFolder = '';
		var mask = '{0}//{1}/{2}/{3}/#comment{4}';
		switch (objectType)
		{
			case '20':
				virtualFolder = 'solution';
				break;
			case '10':
				virtualFolder = 'task';
				break;
			case '60':
				virtualFolder = 'zames';
				mask = '{0}//{1}/{2}/#{3}_{4}';
				break;
			default:
				virtualFolder = '';
				break;
		}
		return String.format(mask,
            window.location.protocol,
            window.location.host,
            virtualFolder,
            sender.attr('objectId'),
            sender.attr('commentId'));
	},
	OnEsc: function (e)
	{
		if (e.keyCode == 27) { this.CloseAllReplyForms(); return false; };
		return true;
	},
	OnReply_Callback: function (comment, context)
	{
		context.TextContainer.setWysiwygContent('');
		this.CloseAllReplyForms();
		if (comment != null)
		{
			this._commentsBuilder.AppendComment(comment, comment.ObjectType == 90);
			this.ScrollToComment(comment);
		}
		this.UnBlockContainer(context.CommentContainer);
		this._waitingForServer = false;
		return false;
	},
	OnReplyClick: function (e)
	{
		var commentContainer = this._commentsBuilder.GetCommentContainer(e.target);
		var commentTypeContainer = this._commentsBuilder.GetCommentTypeContainer(commentContainer);
		var textContainer = this._commentsBuilder.GetCommentTextContainer(commentContainer);
		var commentId = commentContainer.attr('commentId');
		var objectId = commentContainer.attr('objectId');
		var objectType = commentContainer.attr('objectType');
		var chbxAsSolution = $(e.target).closest("div").find("input.asSolution");
		var commentTypeValue = commentTypeContainer.length == 0 ? 0 : commentTypeContainer.val();
		if (this.AllowToReply($(e.target), textContainer))
		{

			//var text = textContainer.val().clearHtml();
			//if (text.length > 0 && !this._waitingForServer)
			if (textContainer.validateWysiwyg() && !this._waitingForServer)
			{
				this._waitingForServer = true;
				this.BlockContainer(commentContainer);
				if (chbxAsSolution.length > 0 && chbxAsSolution[0].checked)
					YouDo.WebServices.TaskService.AddCommentAsSolution(objectId, textContainer.val(), function () { userGate.ReloadWindow(); });
				else
					YouDo.WebServices.CommentsService.ReplyObject(textContainer.val(), commentTypeValue, commentId, objectId, objectType, $.proxy(this.OnReply_Callback, this), null, { CommentContainer: commentContainer, TextContainer: textContainer });
			}
		}
		return false;
	},
	AllowToReply: function (target, focusTarget)
	{
		var result = true;
		if (!userGate.IsLoggedUser())
		{
			userGate.ShowLogin(function () { target.click(); }, Function.emptyFunction);
			result = false;
		}
		if (YouDo.Master.ShowCommentAgreement)
		{
			userGate.ShowAgreement(function () { target.click(); }, Function.emptyFunction);
			result = false;
		}
		return result;
	},
	ShowReplyForm: function (e)
	{
		this.CloseAllReplyForms();
		$(e.target).hide();
		var commentContainer = this._commentsBuilder.GetCommentContainer(e.target);
		var replyContainer = this._commentsBuilder.GetReplyContainer(commentContainer);
		this._commentsBuilder.AppendReplyContainer(commentContainer, true, $.proxy(this.OnEsc, this));
		windowManager.Add($.proxy(this.OnEsc, this), WindowManager.EventType.DocumentKeyDown);
	},
	CloseAllReplyForms: function ()
	{
		var replyForms = this._commentsBuilder.GetReplyContainer().children()
		replyForms.remove();
		this._commentsBuilder.GetReplyButtonContainer().show();
		if (replyForms.length > 0)
			windowManager.Remove(WindowManager.EventType.DocumentKeyDown);
	},
	Load: function (objectId, objectType, objectCreatorId, commentType, scrollToCommentId, onEsc)
	{
		this._currentObjectId = objectId;
		this._currentObjectType = objectType;
		this._currentObjectCreatorId = objectCreatorId;
		this._currentCommentType = commentType;
		this.BlockContainer(this._container);
		YouDo.WebServices.CommentsService.GetCommentsByObjectTypeAndId2(
					objectType,
					objectId,
					$.proxy(this.OnLoad, this),
					null,
					{ ObjectId: objectId, ObjectType: objectType, ObjectCreatorId: objectCreatorId, CommentType: commentType, Container: this._container, ScrollToCommentId: scrollToCommentId, OnEsc: onEsc });
	},
	LoadWall: function (profileId, commentsCount)
	{
		this._currentObjectId = profileId;
		this._commentsCount = commentsCount;
		this._currentObjectType = 'Wall';
		this._currentObjectCreatorId = 0;
		this._currentCommentType = [0];
		this.BlockContainer(this._container);
		YouDo.WebServices.CommentsService.GetWallComments(
					profileId,
					commentsCount,
					$.proxy(this.OnLoad, this),
					null,
					{ ObjectId: profileId, ObjectType: this._currentObjectType, ObjectCreatorId: 0, CommentType: this._currentCommentType, Container: this._container, ScrollToCommentId: 0, OnEsc: null });
	},
	OnLoad: function (comments, context)
	{
		this._container.html('');
		this._commentsBuilder.Render(comments, context);
		this.UnBlockContainer($(context.Container));
		if (context.ScrollToCommentId != null)
		{
			this.ScrollToComment({ Id: context.ScrollToCommentId });
		}
	},
	Builder: function () { return this._commentsBuilder; },
	BlockContainer: function (target) { YouDo.Preloader.Block(target); },
	Refresh: function (e)
	{
		YouDo.Preloader.AppendTo($('div.refresh-comments-preloader'), 16);

		if (this._currentObjectType == 'Wall')
			this.LoadWall(this._currentObjectId, this._commentsCount);
		else
			this.Load(this._currentObjectId, this._currentObjectType, this._currentObjectCreatorId, this._currentCommentType); return false;
		return false;
	},
	UnBlockContainer: function (target) { target.unblock(); },
	ScrollToComment: function (comment)
	{
		var commentContainer = this._commentsBuilder.GetCommentContainerByComment(comment);
		if (commentContainer.length > 0)
		{
			var containerTop = commentContainer.offset().top;
			(this._scrollableContainer == null ? this._body : this._scrollableContainer).animate({ scrollTop: containerTop + 'px' }, 1000, 'swing');
		}
	},
	destruct: function () { }
};
