4 * Namespace for comments
9 * Comment support for WCF
11 * @author Alexander Ebert
12 * @copyright 2001-2019 WoltLab GmbH
13 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
15 WCF
.Comment
.Handler
= Class
.extend({
17 * list of comment buttons per comment
20 _commentButtonList
: { },
23 * list of comment objects
29 * comment container object
41 * number of currently displayed comments
44 _displayedComments
: 0,
47 * button to load next comments
50 _loadNextComments
: null,
53 * buttons to load next responses per comment
56 _loadNextResponses
: { },
60 * @var WCF.Action.Proxy
65 * list of response objects
73 * data of the comment the active guest user is about to create
79 * guest dialog with username input field and recaptcha
84 _permalinkComment
: null,
85 _permalinkResponse
: null,
89 * Initializes the WCF.Comment.Handler class.
91 * @param string containerID
93 init: function(containerID
) {
94 this._commentButtonList
= { };
96 this._containerID
= containerID
;
97 this._displayedComments
= 0;
98 this._loadNextComments
= null;
99 this._loadNextResponses
= { };
100 this._permalinkComment
= null;
101 this._permalinkResponse
= null;
102 this._responseAdd
= null;
103 this._responseCache
= {};
104 this._responseRevert
= null;
105 this._responses
= {};
106 this._scrollTarget
= null;
107 this._onResponsesLoaded
= null;
109 this._container
= $('#' + $.wcfEscapeID(this._containerID
));
110 if (!this._container
.length
) {
111 console
.debug("[WCF.Comment.Handler] Unable to find container identified by '" + this._containerID
+ "'");
115 this._proxy
= new WCF
.Action
.Proxy({
116 success
: $.proxy(this._success
, this)
119 this._initComments();
120 this._initResponses();
123 if (this._container
.data('canAdd')) {
124 if (elBySel('.commentListAddComment .wysiwygTextarea', this._container
[0]) === null) {
125 console
.error("Missing WYSIWYG implementation, adding comments is not available.");
128 require(['WoltLabSuite/Core/Ui/Comment/Add', 'WoltLabSuite/Core/Ui/Comment/Response/Add'], (function (UiCommentAdd
, UiCommentResponseAdd
) {
129 new UiCommentAdd(elBySel('.jsCommentAdd', this._container
[0]));
131 this._responseAdd
= new UiCommentResponseAdd(
132 elBySel('.jsCommentResponseAdd', this._container
[0]),
134 callbackInsert
: (function () {
135 if (this._responseRevert
!== null) {
136 this._responseRevert();
137 this._responseRevert
= null;
145 require(['WoltLabSuite/Core/Ui/Comment/Edit', 'WoltLabSuite/Core/Ui/Comment/Response/Edit'], (function (UiCommentEdit
, UiCommentResponseEdit
) {
146 new UiCommentEdit(this._container
[0]);
147 new UiCommentResponseEdit(this._container
[0]);
150 WCF
.DOMNodeInsertedHandler
.execute();
151 WCF
.DOMNodeInsertedHandler
.addCallback('WCF.Comment.Handler', $.proxy(this._domNodeInserted
, this));
153 WCF
.System
.ObjectStore
.add('WCF.Comment.Handler', this);
155 window
.addEventListener('hashchange', function () {
156 var hash
= window
.location
.hash
;
157 if (hash
&& hash
.match(/.+\/(comment\d+)/)) {
158 var commentId
= RegExp
.$1;
160 // delay scrolling in case a tab menu change was requested
161 window
.setTimeout(function () {
162 var comment
= elById(commentId
);
163 if (comment
) comment
.scrollIntoView({ behavior
: 'smooth' });
168 var hash
= window
.location
.hash
;
169 if (hash
.match(/^#(?:[^\/]+\/)?comment(\d+)(?:\/response(\d+))?/)) {
170 var comment
= elById('comment' + RegExp
.$1);
174 response
= elById('comment' + RegExp
.$1 + 'response' + RegExp
.$2);
176 this._scrollTo(response
, true);
179 // load response on-the-fly
180 this._loadResponseSegment(comment
, RegExp
.$1, RegExp
.$2);
184 this._scrollTo(comment
, true);
188 // load comment on-the-fly
189 this._loadCommentSegment(RegExp
.$1, RegExp
.$2);
194 _scrollTo: function (element
, highlight
) {
195 if (this._scrollTarget
=== null) {
196 this._scrollTarget
= elCreate('span');
197 this._scrollTarget
.className
= 'commentScrollTarget';
199 document
.body
.appendChild(this._scrollTarget
);
202 this._scrollTarget
.style
.setProperty('top', (element
.getBoundingClientRect().top
+ window
.pageYOffset
- 49) + 'px', '');
204 require(['Ui/Scroll'], (function (UiScroll
) {
205 UiScroll
.element(this._scrollTarget
, function () {
207 if (element
.classList
.contains('commentHighlightTarget')) {
208 element
.classList
.remove('commentHighlightTarget');
209 //noinspection BadExpressionStatementJS
213 element
.classList
.add('commentHighlightTarget');
219 _loadCommentSegment: function (commentId
, responseID
) {
220 this._permalinkComment
= elCreate('li');
221 this._permalinkComment
.className
= 'commentPermalinkContainer loading';
222 this._permalinkComment
.innerHTML
= '<span class="icon icon48 fa-spinner"></span>';
223 this._container
[0].insertBefore(this._permalinkComment
, this._container
[0].firstChild
);
225 this._proxy
.setOption('data', {
226 actionName
: 'loadComment',
227 className
: 'wcf\\data\\comment\\CommentAction',
228 objectIDs
: [commentId
],
231 objectID
: this._container
.data('objectID'),
232 objectTypeID
: this._container
.data('objectTypeID'),
233 responseID
: ~~responseID
237 this._proxy
.sendRequest();
240 _loadResponseSegment: function (comment
, commentId
, responseID
) {
241 this._permalinkResponse
= elCreate('li');
242 this._permalinkResponse
.className
= 'commentResponsePermalinkContainer loading';
243 this._permalinkResponse
.innerHTML
= '<span class="icon icon32 fa-spinner"></span>';
244 var responseList
= elBySel('.commentResponseList', comment
);
245 responseList
.insertBefore(this._permalinkResponse
, responseList
.firstChild
);
247 this._proxy
.setOption('data', {
248 actionName
: 'loadResponse',
249 className
: 'wcf\\data\\comment\\CommentAction',
250 objectIDs
: [commentId
],
253 objectID
: this._container
.data('objectID'),
254 objectTypeID
: this._container
.data('objectTypeID'),
255 responseID
: ~~responseID
259 this._proxy
.sendRequest();
263 * Shows a button to load next comments.
265 _handleLoadNextComments: function() {
266 if (this._displayedComments
< this._container
.data('comments')) {
267 if (this._loadNextComments
=== null) {
268 this._loadNextComments
= $('<li class="commentLoadNext showMore"><button class="small">' + WCF
.Language
.get('wcf.comment.more') + '</button></li>').appendTo(this._container
);
269 this._loadNextComments
.children('button').click($.proxy(this._loadComments
, this));
272 this._loadNextComments
.children('button').enable();
274 else if (this._loadNextComments
!== null) {
275 this._loadNextComments
.remove();
280 * Shows a button to load next responses per comment.
282 * @param integer commentID
284 _handleLoadNextResponses: function(commentID
) {
285 var $comment
= this._comments
[commentID
];
286 $comment
.data('displayedResponses', $comment
.find('ul.commentResponseList > li').length
);
288 if ($comment
.data('displayedResponses') < $comment
.data('responses')) {
289 if (this._loadNextResponses
[commentID
] === undefined) {
290 var $difference
= $comment
.data('responses') - $comment
.data('displayedResponses');
291 this._loadNextResponses
[commentID
] = $('<li class="jsCommentLoadNextResponses"><a>' + WCF
.Language
.get('wcf.comment.response.more', { count
: $difference
}) + '</a></li>').appendTo(this._commentButtonList
[commentID
]);
292 this._loadNextResponses
[commentID
].children('a').data('commentID', commentID
).click($.proxy(this._loadResponses
, this));
293 this._commentButtonList
[commentID
].parent().show();
296 var $difference
= $comment
.data('responses') - $comment
.data('displayedResponses');
297 this._loadNextResponses
[commentID
][0].querySelector("a").textContent
= WCF
.Language
.get(WCF
.Language
.get('wcf.comment.response.more', { count
: $difference
}));
300 else if (this._loadNextResponses
[commentID
] !== undefined) {
301 this._loadNextResponses
[commentID
].remove();
306 * Loads next comments.
308 _loadComments: function() {
309 this._loadNextComments
.children('button').disable();
311 this._proxy
.setOption('data', {
312 actionName
: 'loadComments',
313 className
: 'wcf\\data\\comment\\CommentAction',
316 objectID
: this._container
.data('objectID'),
317 objectTypeID
: this._container
.data('objectTypeID'),
318 lastCommentTime
: this._container
.data('lastCommentTime')
322 this._proxy
.sendRequest();
326 * Loads next responses for given comment.
328 * @param object event
330 _loadResponses: function(event
) {
331 this._loadResponsesExecute($(event
.currentTarget
).disable().data('commentID'), false);
335 * Executes loading of comments, optionally fetching all at once.
337 * @param integer commentID
338 * @param boolean loadAllResponses
340 _loadResponsesExecute: function(commentID
, loadAllResponses
) {
341 this._proxy
.setOption('data', {
342 actionName
: 'loadResponses',
343 className
: 'wcf\\data\\comment\\response\\CommentResponseAction',
346 commentID
: commentID
,
347 lastResponseTime
: this._comments
[commentID
].data('lastResponseTime'),
348 loadAllResponses
: (loadAllResponses
? 1 : 0)
352 this._proxy
.sendRequest();
356 * Handles DOMNodeInserted events.
358 _domNodeInserted: function() {
359 this._initComments();
360 this._initResponses();
364 * Initializes available comments.
366 _initComments: function() {
367 var link
= elBySel('link[rel="canonical"]');
372 link
= window
.location
.toString().replace(/#.+$/, '');
375 // check if comments are within a tab menu
376 var tab
= this._container
[0].closest('.tabMenuContent');
378 link
+= '#' + elData(tab
, 'name');
382 var $loadedComments
= false;
383 this._container
.find('.jsComment').each(function(index
, comment
) {
384 var $comment
= $(comment
).removeClass('jsComment');
385 var $commentID
= $comment
.data('commentID');
386 self
._comments
[$commentID
] = $comment
;
389 $comment
[0].id
= 'comment' + $commentID
;
391 var $insertAfter
= $comment
.find('ul.commentResponseList');
392 if (!$insertAfter
.length
) $insertAfter
= $comment
.find('.commentContent');
394 var $container
= $('<div class="commentOptionContainer" />').hide().insertAfter($insertAfter
);
395 self
._commentButtonList
[$commentID
] = $('<ul class="inlineList dotSeparated" />').appendTo($container
);
397 self
._handleLoadNextResponses($commentID
);
398 self
._initComment($commentID
, $comment
);
399 self
._initPermalink($comment
[0], link
);
400 self
._displayedComments
++;
402 $loadedComments
= true;
405 if ($loadedComments
) {
406 this._handleLoadNextComments();
411 * Initializes a specific comment.
413 * @param integer commentID
414 * @param jQuery comment
416 _initComment: function(commentID
, comment
) {
417 if (this._container
.data('canAdd')) {
418 this._initAddResponse(commentID
, comment
);
421 if (comment
.data('canEdit')) {
422 var $editButton
= $('<li><a href="#" class="jsCommentEditButton jsTooltip" title="' + WCF
.Language
.get('wcf.global.button.edit') + '"><span class="icon icon16 fa-pencil" /> <span class="invisible">' + WCF
.Language
.get('wcf.global.button.edit') + '</span></a></li>');
423 $editButton
.appendTo(comment
.find('ul.buttonList:eq(0)'));
426 if (comment
.data('canDelete')) {
427 var $deleteButton
= $('<li><a href="#" class="jsTooltip" title="' + WCF
.Language
.get('wcf.global.button.delete') + '"><span class="icon icon16 fa-times" /> <span class="invisible">' + WCF
.Language
.get('wcf.global.button.delete') + '</span></a></li>');
428 $deleteButton
.data('commentID', commentID
).appendTo(comment
.find('ul.buttonList:eq(0)')).click($.proxy(this._delete
, this));
431 var enableComment
= elBySel('.jsEnableComment', comment
[0]);
433 enableComment
.addEventListener('click', this._enableComment
.bind(this));
437 _enableComment: function (event
) {
438 event
.preventDefault();
440 var comment
= event
.currentTarget
.closest('.comment');
442 this._proxy
.setOption('data', {
443 actionName
: 'enable',
444 className
: 'wcf\\data\\comment\\CommentAction',
445 objectIDs
: [elData(comment
, 'object-id')]
447 this._proxy
.sendRequest();
450 _initPermalink: function(comment
, link
) {
451 var anchor
= elCreate('a');
452 anchor
.href
= link
+ (link
.indexOf('#') === -1 ? '#' : '/') + 'comment' + elData(comment
, 'object-id');
454 var time
= elBySel('.commentContent:not(.commentResponseContent) .containerHeadline time', comment
);
455 time
.parentNode
.insertBefore(anchor
, time
);
456 anchor
.appendChild(time
);
460 * Initializes available responses.
462 _initResponses: function() {
463 var link
= elBySel('link[rel="canonical"]');
468 link
= window
.location
.toString().replace(/#.+$/, '');
471 // check if comments are within a tab menu
472 var tab
= this._container
[0].closest('.tabMenuContent');
474 link
+= '#' + elData(tab
, 'name');
477 for (var commentId
in this._comments
) {
478 if (this._comments
.hasOwnProperty(commentId
)) {
479 elBySelAll('.jsCommentResponse', this._comments
[commentId
][0], (function(response
) {
480 var $response
= $(response
).removeClass('jsCommentResponse');
481 var $responseID
= $response
.data('responseID');
482 this._responses
[$responseID
] = $response
;
484 //noinspection JSReferencingMutableVariableFromClosure
485 response
.id
= 'comment' + commentId
+ 'response' + $responseID
;
487 this._initResponse($responseID
, $response
);
489 //noinspection JSReferencingMutableVariableFromClosure
490 this._initPermalinkResponse(commentId
, response
, $responseID
, link
);
492 var enableResponse
= elBySel('.jsEnableResponse', response
);
493 if (enableResponse
) {
494 enableResponse
.addEventListener('click', this._enableCommentResponse
.bind(this));
501 _enableCommentResponse: function (event
) {
502 event
.preventDefault();
504 var response
= event
.currentTarget
.closest('.commentResponse');
506 this._proxy
.setOption('data', {
507 actionName
: 'enableResponse',
508 className
: 'wcf\\data\\comment\\CommentAction',
511 responseID
: elData(response
, 'object-id')
515 this._proxy
.sendRequest();
518 _initPermalinkResponse: function (commentId
, response
, responseId
, link
) {
519 var anchor
= elCreate('a');
520 anchor
.href
= link
+ (link
.indexOf('#') === -1 ? '#' : '/') + 'comment' + commentId
+ '/response' + responseId
;
522 var time
= elBySel('.commentResponseContent .containerHeadline time', response
);
523 time
.parentNode
.insertBefore(anchor
, time
);
524 anchor
.appendChild(time
);
528 * Initializes a specific response.
530 * @param integer responseID
531 * @param jQuery response
533 _initResponse: function(responseID
, response
) {
534 if (response
.data('canEdit')) {
535 var $editButton
= $('<li><a href="#" class="jsCommentResponseEditButton jsTooltip" title="' + WCF
.Language
.get('wcf.global.button.edit') + '"><span class="icon icon16 fa-pencil" /> <span class="invisible">' + WCF
.Language
.get('wcf.global.button.edit') + '</span></a></li>');
536 $editButton
.data('responseID', responseID
).appendTo(response
.find('ul.buttonList:eq(0)'));
539 if (response
.data('canDelete')) {
540 var $deleteButton
= $('<li><a href="#" class="jsTooltip" title="' + WCF
.Language
.get('wcf.global.button.delete') + '"><span class="icon icon16 fa-times" /> <span class="invisible">' + WCF
.Language
.get('wcf.global.button.delete') + '</span></a></li>');
543 $deleteButton
.data('responseID', responseID
).appendTo(response
.find('ul.buttonList:eq(0)')).click(function(event
) { self
._delete(event
, true); });
548 * Initializes the UI elements to add a response.
550 * @param integer commentID
551 * @param jQuery comment
553 _initAddResponse: function(commentID
, comment
) {
554 var $placeholder
= $('<li class="jsCommentShowAddResponse"><a>' + WCF
.Language
.get('wcf.comment.button.response.add') + '</a></li>').data('commentID', commentID
).click($.proxy(this._showAddResponse
, this)).appendTo(this._commentButtonList
[commentID
]);
555 this._commentButtonList
[commentID
].parent().show();
559 * Displays the UI elements to create a response.
561 * @param object event
563 _showAddResponse: function(event
) {
564 event
.preventDefault();
567 if (this._onResponsesLoaded
!== null) {
572 if (this._responseAdd
=== null) {
573 console
.error("Missing response API.");
577 var responseContainer
= this._responseAdd
.getContainer();
578 if (responseContainer
=== null) {
583 if (this._responseRevert
!== null) {
584 this._responseRevert();
585 this._responseRevert
= null;
588 var $placeholder
= $(event
.currentTarget
);
589 var $commentID
= $placeholder
.data('commentID');
591 this._onResponsesLoaded
= (function() {
594 if (responseContainer
.parentNode
&& responseContainer
.parentNode
.classList
.contains('jsCommentResponseAddContainer')) {
595 // strip the parent element, it is used as a work-around
596 elRemove(responseContainer
.parentNode
);
599 var commentOptionContainer
= this._commentButtonList
[$commentID
][0].closest('.commentOptionContainer');
600 commentOptionContainer
.parentNode
.insertBefore(responseContainer
, commentOptionContainer
.nextSibling
);
602 if (typeof this._responseCache
[$commentID
] === 'string') {
603 this._responseAdd
.setContent(this._responseCache
[$commentID
]);
606 this._responseAdd
.setContent('');
609 this._responseRevert
= (function () {
610 this._responseCache
[$commentID
] = this._responseAdd
.getContent();
612 elRemove(responseContainer
);
616 this._onResponsesLoaded
= null;
619 if ($placeholder
.prev().hasClass('jsCommentLoadNextResponses')) {
620 this._loadResponsesExecute($commentID
, true);
621 $placeholder
.parent().children('.button').disable();
624 this._onResponsesLoaded();
629 * Shows a confirmation message prior to comment or response deletion.
631 * @param object event
632 * @param boolean isResponse
634 _delete: function(event
, isResponse
) {
635 event
.preventDefault();
636 WCF
.System
.Confirmation
.show(WCF
.Language
.get('wcf.comment.delete.confirmMessage'), $.proxy(function(action
) {
637 if (action
=== 'confirm') {
639 objectID
: this._container
.data('objectID'),
640 objectTypeID
: this._container
.data('objectTypeID')
642 if (isResponse
!== true) {
643 $data
.commentID
= $(event
.currentTarget
).data('commentID');
646 $data
.responseID
= $(event
.currentTarget
).data('responseID');
649 this._proxy
.setOption('data', {
650 actionName
: 'remove',
651 className
: 'wcf\\data\\comment\\CommentAction',
656 this._proxy
.sendRequest();
662 * Handles successful AJAX requests.
665 * @param string textStatus
666 * @param jQuery jqXHR
668 _success: function(data
, textStatus
, jqXHR
) {
669 switch (data
.actionName
) {
674 case 'enableResponse':
675 this._enableResponse(data
);
679 this._insertComment(data
);
683 this._insertComments(data
);
687 this._insertResponse(data
);
690 case 'loadResponses':
691 this._insertResponses(data
);
699 WCF
.DOMNodeInsertedHandler
.execute();
702 _enable: function(data
) {
703 if (data
.returnValues
.commentID
) {
704 var comment
= elBySel('.comment[data-object-id="' + data
.returnValues
.commentID
+ '"]', this._container
[0]);
706 elData(comment
, 'is-disabled', 0);
707 var badge
= elBySel('.jsIconDisabled', comment
);
708 if (badge
) elRemove(badge
);
710 var enableLink
= elBySel('.jsEnableComment', comment
);
711 if (enableLink
) elRemove(enableLink
.parentNode
);
716 _enableResponse: function(data
) {
717 if (data
.returnValues
.responseID
) {
718 var response
= elBySel('.commentResponse[data-object-id="' + data
.returnValues
.responseID
+ '"]', this._container
[0]);
720 elData(response
, 'is-disabled', 0);
721 var badge
= elBySel('.jsIconDisabled', response
);
722 if (badge
) elRemove(badge
);
724 var enableLink
= elBySel('.jsEnableResponse', response
);
725 if (enableLink
) elRemove(enableLink
.parentNode
);
730 _insertComment: function (data
) {
731 if (data
.returnValues
.template
=== '') {
732 elRemove(this._permalinkComment
);
734 // comment id is invalid or there is a mismatch, silently ignore it
738 $(data
.returnValues
.template
).insertBefore(this._permalinkComment
);
739 var comment
= this._permalinkComment
.previousElementSibling
;
740 comment
.classList
.add('commentPermalinkContainer');
742 elRemove(this._permalinkComment
);
743 this._permalinkComment
= comment
;
745 if (data
.returnValues
.response
) {
746 this._permalinkResponse
= elCreate('li');
747 this._permalinkResponse
.className
= 'commentResponsePermalinkContainer loading';
748 this._permalinkResponse
.innerHTML
= '<span class="icon icon32 fa-spinner"></span>';
749 var responseList
= elBySel('.commentResponseList', comment
);
750 responseList
.insertBefore(this._permalinkResponse
, responseList
.firstChild
);
752 this._insertResponse({
754 template
: data
.returnValues
.response
759 //noinspection BadExpressionStatementJS
762 comment
.classList
.add('commentHighlightTarget');
765 _insertResponse: function(data
) {
766 if (data
.returnValues
.template
=== '') {
767 elRemove(this._permalinkResponse
);
769 // comment id is invalid or there is a mismatch, silently ignore it
773 $(data
.returnValues
.template
).insertBefore(this._permalinkResponse
);
774 var response
= this._permalinkResponse
.previousElementSibling
;
775 response
.classList
.add('commentResponsePermalinkContainer');
777 elRemove(this._permalinkResponse
);
778 this._permalinkResponse
= response
;
780 //noinspection BadExpressionStatementJS
783 response
.classList
.add('commentHighlightTarget');
787 * Inserts previously loaded comments.
791 _insertComments: function(data
) {
793 $(data
.returnValues
.template
).insertBefore(this._loadNextComments
);
795 // update time of last comment
796 this._container
.data('lastCommentTime', data
.returnValues
.lastCommentTime
);
798 // check if permalink comment has been loaded and remove it from view
799 if (this._permalinkComment
) {
800 var commentId
= elData(this._permalinkComment
, 'object-id');
802 if (elBySel('.comment[data-object-id="' + commentId
+ '"]:not(.commentPermalinkContainer)', this._container
[0]) !== null) {
803 elRemove(this._permalinkComment
);
804 this._permalinkComment
= null;
808 this._initComments();
812 * Inserts previously loaded responses.
816 _insertResponses: function(data
) {
817 var $comment
= this._comments
[data
.returnValues
.commentID
];
820 $(data
.returnValues
.template
).appendTo($comment
.find('ul.commentResponseList'));
822 // update time of last response
823 $comment
.data('lastResponseTime', data
.returnValues
.lastResponseTime
);
825 // update button state to load next responses
826 this._handleLoadNextResponses(data
.returnValues
.commentID
);
828 // check if permalink response has been loaded and remove it from view
829 if (this._permalinkResponse
) {
830 var responseId
= elData(this._permalinkResponse
, 'object-id');
832 if (elBySel('.commentResponse[data-object-id="' + responseId
+ '"]:not(.commentPermalinkContainer)', this._container
[0]) !== null) {
833 elRemove(this._permalinkResponse
);
834 this._permalinkResponse
= null;
838 // check if there is a pending reply request
839 if (this._onResponsesLoaded
!== null) this._onResponsesLoaded();
843 * Removes a comment or response from list.
847 _remove: function(data
) {
848 if (data
.returnValues
.commentID
) {
849 this._comments
[data
.returnValues
.commentID
].remove();
850 delete this._comments
[data
.returnValues
.commentID
];
853 var $response
= this._responses
[data
.returnValues
.responseID
];
854 var $comment
= this._comments
[$response
.parents('li.comment:eq(0)').data('commentID')];
856 // decrease response counter because a correct response count
857 // is required in _handleLoadNextResponses()
858 $comment
.data('responses', parseInt($comment
.data('responses')) - 1);
860 var $commentResponseList
= $response
.parent();
863 if (!$commentResponseList
.children().length
) {
864 // make '.commentResponseList' accessible via CSS'
866 $commentResponseList
.empty();
869 delete this._responses
[data
.returnValues
.responseID
];
873 _prepareEdit: function() { console
.warn("This method is no longer supported."); },
874 _keyUp: function() { console
.warn("This method is no longer supported."); },
875 _save: function() { console
.warn("This method is no longer supported."); },
876 _failure: function() { console
.warn("This method is no longer supported."); },
877 _edit: function() { console
.warn("This method is no longer supported."); },
878 _update: function() { console
.warn("This method is no longer supported."); },
879 _createGuestDialog: function() { console
.warn("This method is no longer supported."); },
880 _keyDown: function() { console
.warn("This method is no longer supported."); },
881 _submit: function() { console
.warn("This method is no longer supported."); },
882 _keyUpEdit: function() { console
.warn("This method is no longer supported."); },
883 _saveEdit: function() { console
.warn("This method is no longer supported."); },
884 _cancelEdit: function() { console
.warn("This method is no longer supported."); }
888 * Namespace for comment responses
890 WCF
.Comment
.Response
= { };