1$(function() { 2 var CHANNELS = { 3 NEW_COMMENT : 'new_comment' 4 ,DELETE_COMMENT : 'delete_comment' 5 ,PAGE_USERS : 'page_users' 6 ,TYPING : 'typing' 7 }; 8 var CONSTANTS = { 9 TYPING_INTERVAL : 3000 10 ,MAX_SCROLL : 9007199254740991 11 ,MAX_SHOW_TYPING_USERS : 3 12 ,MAX_COMMENTS_PER_PAGE_DIRECTION_DESC : 100 13 }; 14 var SHARED_SELECTORS = { 15 SCROLL_TO : '.comments-container' 16 }; 17 18 var DomHelper = {}; 19 DomHelper.findForms = function($el) { 20 return $el.find('.gc-comment-form'); 21 }; 22 23 DomHelper.removeCommentBlock = function($block) { 24 $block.hide(500); 25 setTimeout(function(){$block.remove()}, 500); 26 }; 27 28 var TreeWidget = function($tree) { 29 var that = this; 30 31 runOneTimeOnElement($tree, 'gc-comments-tree-widget', function($el) { 32 var typingWidget = new TypingBlockWidget($el); 33 34 that.getTypingWidget = function() { 35 return typingWidget; 36 }; 37 38 that.init($el); 39 40 return that; 41 }); 42 43 }; 44 45 TreeWidget.create = function($tree) { 46 return new this($tree) 47 }; 48 49 TreeWidget.applyAccess = function (val, role, $html) { 50 if (!val) {// todo пÑовеÑка валидноÑÑи window.userInfo.isAdmin вÑнеÑение ÑÐ°ÐºÐ¸Ñ Ð¿ÑовеÑок в какое Ñо одно меÑÑо 51 $('[data-access-content-type=link]', $html).each(function(){ 52 var $el = $(this); 53 $el.replaceWith($el.html()); 54 }); 55 $('[data-access*='+role+']', $html).each(function(){ 56 var $el = $(this); 57 $el.remove(); 58 }); 59 } 60 else { 61 $('[data-access*='+role+']', $html).removeClass('hide'); 62 } 63 }; 64 65 /** 66 * ÐоказÑÐ²Ð°ÐµÑ ÑпÑÑÑаннÑе комменÑаÑии (Ð´Ð»Ñ isCollapsible) 67 * @param obj 68 * @returns {boolean} 69 */ 70 TreeWidget.moreComments = function(obj) { 71 var hiddenComments = $(obj).parent().nextAll('.comment-level.hide'); 72 if ( hiddenComments.length ) { 73 hiddenComments 74 .slice(Math.max(hiddenComments.length - 10, 0), hiddenComments.length) 75 .removeClass('hide'); 76 } 77 var length = $(obj).parent().nextAll('.comment-level.hide').length; 78 79 if (length < 1) { 80 $(obj).hide(); 81 $(obj).parents('.comments-container:first').find('.more:first').removeClass('hide'); 82 } else { 83 var hiddenCount = length; 84 if ($(obj).attr('data-current-count')) { 85 hiddenCount = parseInt($(obj).attr('data-current-count')) - length; 86 } 87 $(obj).find('span.count').html(hiddenCount); 88 } 89 90 return false; 91 }; 92 93 TreeWidget.resize = function($tree) { 94 var scrollToBottomSelector = $tree.data('scroll-to-bottom'); 95 if (scrollToBottomSelector) { 96 // debugger; 97 var $container = $tree.find('.comments-container:first'); 98 var formOuterHeight = $tree.find('.gc-comment-form').outerHeight(true); 99 var height = $container.parent().height(); 100 //console.log(height, formOuterHeight); 101 if ( $( window ).width() > 767 ) { 102 $container.css('height', (height - formOuterHeight) + 'px'); 103 } else if ( $( window ).height() < ( $container.outerHeight(true) + 44 ) ) { 104 $container.css('height', ($( window ).height() - formOuterHeight - 44 ) + 'px'); 105 } 106 else { 107 height = $container.parent().parent().height(); 108 $container.css('height', (height - formOuterHeight) + 'px'); 109 } 110 111 112 var first = $tree.find(SHARED_SELECTORS.SCROLL_TO).get(0); 113 first.scrollTop = first.scrollHeight; 114 } 115 }; 116 117 function validateUrl(value) { 118 return /^\/\/.*fs.*\.(?:getcourse|gcrc).*\/fileservice\/.*\/thumbn
118ail\/.*$/i.test(value) 119 || value === "/public/img/default_profile_50.png"; 120 } 121 122 function makeThumbnail(thumbnail) { 123 let isValid = false; 124 const srcMatches = thumbnail.match(/src=["'](.*?)["']/); 125 if (srcMatches !== null) { 126 if (validateUrl(srcMatches[1])) { 127 isValid = true; 128 } 129 } 130 let src = isValid ? srcMatches[1] : "/public/img/default_profile_50.png"; 131 return '<img loading="lazy" class="user-profile-image user-default-profile-image" src="' 132 + src 133 + '" width="50">'; 134 } 135 136 TreeWidget.prototype = { 137 init : function($tree) { 138 this.initScroll($tree); 139 this.initForms($tree); 140 this.initComments($tree); 141 this.initCommentsQueue($tree); 142 this.initMoreLinks($tree); 143 this.initDownloadComments($tree); 144 this.initHelpdesk($tree); 145 this.initWebSocket($tree, window.accountUserWebSocketConnection); 146 } 147 ,initScroll : function($tree) { 148 TreeWidget.resize($tree); 149 $(window).resize(function () { 150 TreeWidget.resize($tree); 151 }); 152 } 153 ,initForms : function($tree) { 154 var that = this; 155 DomHelper.findForms($tree).each(function (index, el) { 156 CommentFormWidget.create($(el)); 157 }); 158 } 159 ,initComments : function($tree) { 160 var that = this; 161 $tree.find('.gc-comment').each(function (index, el) { 162 CommentWidget.create($(el)); 163 }); 164 } 165 ,initCommentsQueue : function($tree) { 166 $tree.data('queue', []); 167 $tree.data('paused', 0); 168 var $button = $tree.find('.pause'); 169 $tree.data('pause-button', $button); 170 $button.click(function() { 171 if (!$tree.data('paused')) { 172 $tree.data('paused', 1); 173 $(this).find('.text').html('<span class="fa fa-play"></span> ÐклÑÑиÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ðµ'); 174 } 175 else { 176 $tree.data('paused', 0); 177 var l = $tree.data('queue').length; 178 for(var i = 0; i < l; i++) { 179 var comment = $tree.data('queue').shift(); 180 addComment(comment.objectId, comment.objectTypeId, comment.settings, comment.html); 181 } 182 $(this).find('.text').html('<span class="glyphicon glyphicon-pause"></span> ' + ( window.language == 'en' ? "Disable autoupdate" : "ÐÑклÑÑиÑÑ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ðµ" )); 183 $(this).find('.value').html(''); 184 } 185 }); 186 187 var chatCollapsed = window.gcGetCookie("chatCollapsed"); 188 189 $tree.parent().find('.chat-collapse-btn').click( function(e ) { 190 $tree.parent().addClass('chat-collapsed') 191 window.gcSetCookie("chatCollapsed", 1) 192 $('.gc-both-main-content').removeClass('container-auto-width'); 193 194 if ( $tree.parent().find('.chat-expand-btn').length == 0 ) { 195 $expandBtn = $('<div class="chat-expand-btn"><span class="glyphicon glyphicon-triangle-left"></span></div>') 196 $tree.parent().click(function () { 197 $(this).removeClass('chat-collapsed'); 198 $('.gc-both-main-content').addClass('container-auto-width'); 199 window.gcSetCookie("chatCollapsed", 0) 200 }); 201 202 $expandBtn.appendTo($tree.parent()); 203 } 204 e.stopPropagation(); 205 e.preventDefault(); 206 }) 207 if ( chatCollapsed == 1 ) { 208 $tree.parent().find('.chat-collapse-btn').click(); 209 } 210 } 211 ,initMoreLinks : function($tree) { 212 $tree.find('.more a').click(function() { 213 var that = this; 214 $(this).parent().append('<i class="fa fa-spinner fa-spin"></i>'); 215 var $container = $($(this).parents('.comments-container').get(0)); 216 var settings = $($container.find('.settings-level-1').get(0)).find('textarea'); 217 var asChat = $(this).data('as-chat'); 218 var direction = $(this).data('direction'); 219 220 ajaxCall('/cms/comment/getTree', { 221 settings : settings.html() 222 ,page : $(this).data('page') + 1 223 ,as_chat : asChat 224 }, {}, function(response) { 225 if (!response.hasNext) { 226 $(that).hide(); 227 } 228 $(that).parent().find('.fa-spinner').remove(); 229 $(that).data('page', $(that).data('page') + 1); 230 $(that).data('clicked', 1); 231 var $container = $($(that).parents('.comments-container').get(0)); 232 var $commentsBlock = $($container.find('.comments').get(0)); 233 var html = []; 234 $.each(response.comments, function(index, comment) { 235 html.push(comment.html); 236 }); 237 $(that).html(response.linkText); 238 if (asChat) { 239 var currentTopElement = $commentsBlock.find('.gc-comment').first(); 240 var currentBlockHeight = $commentsBlock.outerHeight(); 241 $commentsBlock.prepend(html.join('')); 242 // ÑкÑоллим окно ÑообÑений к поÑÐ»ÐµÐ´Ð½ÐµÐ¼Ñ Ð¿ÑоÑиÑÐ°Ð½Ð½Ð¾Ð¼Ñ 243 $container.scrollTop( currentBlockHeight + currentTopElement.offset().top + 120 - 40 ); 244 } 245 else { 246 if (direction === 'asc') { 247 $commentsBlock.prepend(html.reverse().join('')); 248 } 249 else { 250 $commentsBlock.append(html.join('')); 251 } 252 } 253 }, function() { 254 if ( typeof window.checkSelectedComment == 'function' ) { 255 window.checkSelectedComment(); 256 } 257 }); 258 return false;
259 }) 260 } 261 ,initWebSocket : function($tree, connection) { 262 if (!connection) { 263 return; 264 } 265 this.initWebSocketPageUsers($tree, connection); 266 this.initWebSocketTreeUsers($tree, connection); 267 this.initWebSocketNewComments($tree, connection); 268 this.initWebSocketUserTyping($tree, connection); 269 } 270 ,initWebSocketPageUsers: function ($tree, connection) { 271 var treeChannelSuffix = $tree.data('tree-channel-suffix') || $tree.data('tree-id'); 272 connection.subscribeChannel(CHANNELS.PAGE_USERS + connection.pageKey + '_' + treeChannelSuffix, function (message, json) { 273 $tree.find('.online-users-count').html(json.stat.connections.unique + (window.language == 'en' ? ' online' : ' онлайн')); 274 }); 275 } 276 ,initWebSocketTreeUsers: function ($tree, connection) { 277 var treeId = $tree.data('tree-id'); 278 var treeChannelSuffix = $tree.data('tree-channel-suffix') || treeId; 279 connection.subscribeChannel( 280 CHANNELS.PAGE_USERS + '_' + treeChannelSuffix, 281 function (message, json) { 282 $('.' + treeId).each(function (index, el) { 283 var cnt = json.stat.connections.unique; 284 var $el = $(el); 285 var html = ''; 286 if (cnt > 0) { 287 html = cnt + ' ' + Yii.t('common','online'); 288 } 289 $el.find('.online-users-count').html(html); 290 }); 291 } 292 ); 293 } 294 ,initWebSocketNewComments : function($tree, connection, oldTreeId) { 295 var that = this; 296 if (!connection) { 297 console.log('no socket connection'); 298 return; 299 } 300 var userChannelSuffix = $tree.data('user-channel-suffix') || window.userChannelSuffix || window.accountUserId; 301 var treeChannelSuffix = $tree.data('tree-channel-suffix') || $tree.data('tree-id'); 302 if (oldTreeId) { 303 var oldTreeChannelSuffix = $tree.data('old-tree-channel-suffix') || oldTreeId; 304 connection.unsubscribeChannel(CHANNELS.NEW_COMMENT+oldTreeChannelSuffix); 305 connection.unsubscribeChannel(CHANNELS.NEW_COMMENT+oldTreeChannelSuffix+userChannelSuffix); 306 connection.unsubscribeChannel(CHANNELS.DELETE_COMMENT+oldTreeChannelSuffix); 307 } 308 connection.subscribeChannel(CHANNELS.NEW_COMMENT+treeChannelSuffix, function(message, json){newComment(json)}); 309 connection.subscribeChannel(CHANNELS.NEW_COMMENT+treeChannelSuffix+userChannelSuffix, function(message, json){newComment(json)}); 310 connection.subscribeChannel(CHANNELS.DELETE_COMMENT+treeChannelSuffix, function(message, json){ 311 $.each(json.comment_ids, function (index, id) { 312 DomHelper.removeCommentBlock($('.comment'+id+'top')); 313 }); 314 }); 315 function newComment(json) { 316 if ('string' === (typeof json)) { 317 try { 318 json = JSON.parse(json); 319 } catch (e) { 320 console.log(e, json); 321 } 322 } 323 var commentId = json.comment_id; 324 if (!commentId) { 325 console.log("empty comment id"); 326 return; 327 } 328 that.getTypingWidget().removeUser(json.user_id); 329 setTimeout( 330 function () { 331 addComment(json.object_id, json.object_type_id, json.settings, json.html, true); 332 }, 333 //( Math.random() * 2000 ) + 2000 334 0 335 ); 336 } 337 } 338 ,initWebSocketUserTyping : function($tree, connection, oldTreeId) { 339 if (!connection || $tree.data('tree-id').match(/need_create/)) { 340 return; 341 } 342 if ($tree.hasClass('comments-tree-show-typing')) { 343 var that = this; 344 var treeChannelSuffix = $tree.data('tree-channel-suffix') || $tree.data('tree-id'); 345 if (oldTreeId) { 346 var oldTreeChannelSuffix = $tree.data('old-tree-channel-suffix') || oldTreeId; 347 connection.unsubscribeChannel(CHANNELS.TYPING+'_'+oldTreeChannelSuffix); 348 } 349 connection.subscribeChannel(CHANNELS.TYPING + '_' + treeChannelSuffix, function(message, json){ 350 that.getTypingWidget().addUser(json.user_id, json.user_name, makeThumbnail(json.user_user_thumbnail)); 351 }); 352 } 353 }, 354 initDownloadComments: function ($tree) { 355 $tree.find('a.download-csv').click(function() { 356 var that = this; 357 var $container = $($tree.find('.comments-container').get(0)); 358 var settings = $($container.find('.settings-level-1').get(0)).find('textarea'); 359 if ( settings.html() ) { 360 window.location = '/cms/comment/downloadTree?settings=' + settings.html(); 361 } else { 362 alert('ÐÑибка ÑкÑпоÑÑа'); 363 } 364 return false;
365 }) 366 }, 367 initHelpdesk: function ($tree) { 368 $tree.find('a.helpdesk-btn').click(function() { 369 var confirmText = $(this).data('confirm-text') ?? Yii.t('helpdesk', 'ÐÑ ÑвеÑенÑ?'); 370 if (!confirm(confirmText)) { 371 return; 372 } 373 $(this).attr('disabled', 'disabled'); 374 ajaxCall($(this).data('href'), {}, {}, function(response) { 375 window.location.reload(); 376 }); 377 }); 378 }, 379 }; 380 381 var CommentFormWidget = function($form) { 382 var that = this; 383 384 runOneTimeOnElement($form, 'gc-comment-form-widget', function($el) { 385 that.init($el); 386 387 return that; 388 }); 389 }; 390 391 CommentFormWidget.create = function($form) { 392 return new this($form) 393 }; 394 395 CommentFormWidget.THREAD_COMMENT_HEIGHT = 28; 396 CommentFormWidget.REPLY_COMMENT_HEIGHT = 28; 397 398 CommentFormWidget.uploadButtonIndex = 0; 399 400 CommentFormWidget.prototype = { 401 textAreaHeight : undefined 402 ,init : function($form) { 403 this.initForm($form); 404 this.initTextArea($form, window.accountUserWebSocketConnection); 405 this.initUploaders($form); 406 this.initModalWindow($form); 407 this.initTemplates($form); 408 409 if (window.GcEmojiHelper) { 410 window.GcEmojiHelper.initEmojiTextAreas($form); 411 } 412 } 413 ,initForm: function ($form) { 414 $form.find('form').submit(function (event) { 415 416 var buttonTextGo = 'ÐÑпÑавлÑеÑÑÑ'; 417 418 if (typeof Yii != 'undefined') { 419 buttonTextGo = Yii.t( "common", "Go" ); 420 } 421 422 var $this = $(this); 423 var $button = $this.find('button'); 424 $button.attr('disabled', 'disabled'); 425 var $buttonText = $button.find('.text'); 426 $buttonText.data('old', $buttonText.html()); 427 $buttonText.html(buttonTextGo); 428 var data = $this.serialize(); 429 commentAddAjax($this, data, null, function () { 430 $this.find('button').removeAttr('disabled'); 431 $buttonText.html($buttonText.data('old')); 432 }); 433 return false; 434 }); 435 } 436 ,initTextArea : function($form, webSocketConnection) { 437 var $f = $form; 438 var that = this; 439 var $tree = $form.parents('.comments-tree'); 440 441 if (!!window.presaveInLocalStorageComments) { 442 var answerId = $form.closest('.user-answer').data('id'), 443 localStorageKey = 'new-comment-for-answer-' + answerId, 444 localStorageValue = localStorage.getItem(localStorageKey); 445 446 if (!!answerId && !!localStorageValue) { 447 $form.find('.new-comment-textarea').val(localStorageValue); 448 } 449 } 450 451 $form.find('.new-comment-textarea') 452 .css('max-height', 200 + 'px') 453 .autosize() 454 .css('min-height', CommentFormWidget.REPLY_COMMENT_HEIGHT + 'px') 455 .css('height', CommentFormWidget.REPLY_COMMENT_HEIGHT + 'px') 456 .keyup(function(event) { 457 var $that = $(this); 458 if ($that.val().length > 0) { 459 $that.parents('.new-comment').addClass('active'); 460 var $form = $that.parents('form'); 461 if( event.keyCode == 13 && ( event.ctrlKey ) && ( ( $f.data('submit-on-enter') && ! event.shiftKey ) || event.ctrlKey ) ) { 462 $form.submit(); 463 } 464 } 465 else { 466 $that.parents('.new-comment').removeClass('active'); 467 } 468 469 if (that.textAreaHeight != $f.height()) { 470 TreeWidget.resize($tree); 471 that.textAreaHeight = $f.height(); 472 } 473 if (webSocketConnection && $tree.hasClass('comments-tree-show-typing')) { 474 var treeChannelSuffix = $tree.data('tree-channel-suffix') || $tree.data('tree-id'); 475 var channel = CHANNELS.TYPING+'_'+treeChannelSuffix; 476 if (!$that.data('typing')) { 477 $that.data('typing', 1); 478 if (webSocketConnection && webSocketConnection.getSocket()) { 479 webSocketConnection.getSocket().emit('message', { 480 json: { 481 channel: channel, 482 user_id: window.accountUserId, 483 user_name: window.accountSafeUserName, 484 user_user_thumbnail: window.accountUserThumbnail 485 } 486 }); 487 } 488 setTimeout(function() { 489 $that.data('typing', 0) 490 }, CONSTANTS.TYPING_INTERVAL); 491 } 492 } 493 }).change(function(event) { 494 var value = $(this).val(); 495 496 if (value.length > 0) { 497 if (!!window.presaveInLocalStorageComments) { 498 localStorage.setItem(localStorageKey, value); 499 } 500 $(this).parents('.new-comment').addClass('active'); 501 } else { 502 if (!!window.presaveInLocalStorageComments) { 503 localStorage.removeItem(localStorageKey); 504 } 505 $(this).parents('.new-comment').removeClass('active'); 506 } 507 }).focus(function(event){ 508 $tree.trigger('tree:textarea:focused'); 509 }); 510 511 $form.find('.new-comment-textarea-level-1') 512 .autosize() 513 .css('min-height', CommentFormWidget.THREAD_COMMENT_HEIGHT + 'px') 514 .css('height', CommentFormWidget.THREAD_COMMENT_HEIGHT + 'px') 515 ; 516 TreeWidget.resize($form.parents('.comments-tree')); 517 this.textAreaHeight = $form.height(); 518 } 519 ,initModalWindow : function($form) { 520 $form.find('.auth-link').click(function(e) { 521 var active = window.gcModalActive(); 522 active && active.hide(); 523 window.gcGetDefaultModalAuth().show(); 524 525 return false;
526 }); 527 } 528 ,initUploaders : function(form) { 529 if (!window.userInfo.isInAccount) { 530 //return; 531 } 532 this.initUploader( 533 form.find('.comment-attach-file-link'), function($el, $uploader) { 534 $uploader.insertAfter($el.parents('.new-comment').find('.btn-send')); 535 }); 536 this.initUploader( 537 form.find('.comment-attach-file-for-edit-link'), 538 function($el, $uploader) { 539 $el.append($uploader); 540 } 541 ); 542 } 543 ,initUploader : function($el, insertCallback, afterCreateCallback) { 544 var $uploader = $('<div class="file-uploader" style="max-height: 100px; overflow-y: auto;">'); 545 $uploader.append('<div class="upload-button"></div>'); 546 $uploader.append('<input type="hidden" class="upload-value" name="GetCourseComment[files]">'); 547 insertCallback($el, $uploader); 548 var $button = $uploader.find('.upload-button'); 549 $button.attr('id', 'comment-upload-button' + (CommentFormWidget.uploadButtonIndex++)); 550 var useFileTypes = $el.parents('.comment-form-wrapper').attr('data-use-file-types'); 551 552 // в завиÑимоÑÑи Ð¾Ñ useFileTypes менÑеÑÑÑ Ð¿Ð¾Ð²ÐµÐ´ÐµÐ½Ð¸Ðµ виджеÑа (вÑÐ±Ð¾Ñ Ñипов аÑÑаÑей) 553 var options = { 554 valueElemSelector: $uploader.find('.upload-value'), 555 userId: window.accountUserId, 556 buttonText: '<i class="glyphicon glyphicon-paperclip"></i>', 557 width: 145, 558 removeCompleted: true, 559 other : { 560 onClearQueue : function() { 561 setTimeout(function() { 562 TreeWidget.resize($el.parents('.comments-tree')); 563 }, 1000); 564 }, 565 } 566 }; 567 if (useFileTypes === '1') { 568 options = { 569 valueElemSelector: $uploader.find('.upload-value'), 570 userId: window.accountUserId, 571 buttonText: '<i class="glyphicon glyphicon-paperclip"></i>', 572 width: 145, 573 itemTemplate : '<div class="uploadifive-queue-item"><span class="filename"></span><div class="close"></div>' + 574 '<p class="type_block"></p>' + 575 '<span class="fileinfo"></span>' + 576 '<div class="progress" <div class="progress-bar"></div></div></div>', 577 removeCompleted: true, 578 other : { 579 onClearQueue : function() { 580 setTimeout(function() { 581 TreeWidget.resize($el.parents('.comments-tree')); 582 }, 1000); 583 }, 584 onCancel : function(file) { 585 let hash = file.hash; 586 $hiddenInputEl = $(options.valueElemSelector); 587 let value = $hiddenInputEl.val(); 588 if (value) { 589 let object = JSON.parse(value); 590 object.forEach((item, index, array) => { 591 if (item.hash === hash) { 592 object.splice(index, 1) 593 } 594 }); 595 $hiddenInputEl.val(JSON.stringify(object)); 596 } 597 }, 598 599 onUploadComplete: function (file , res) { 600 var hash = res; 601 file.hash = hash; 602 $hiddenInputEl = $(options.valueElemSelector); 603 let ajaxUrl = '/pl/telegram/control/file/check-file'; 604 if (window.maxEnabledFeature === true) { 605 ajaxUrl = '/pl/inbox-file/check-file'; 606 } 607 608 ajaxCall(ajaxUrl, 609 {hash: hash, validate: false}, 610 {method: 'get'}, 611 function (response) { 612 if (response.success === true) { 613 let newContent = response.data.content; 614 var fileinfo_text = $(newContent).find('.fileinfo').html(); 615 616 file.queueItem.find('.fileinfo').html(fileinfo_text); 617 618 var select = $(newContent).find('.change-upload-type'); 619 select.attr('attr_hash', hash); 620 var type_block = 621 $('<span>'+Yii.t('widgets', 'ÐÑпÑавиÑÑ Ñайл как')+': ' + 622 '<span class="type_select"></span></span>'); 623 type_block.find('.type_select').append(select); 624 file.queueItem.find('.type_block').html(type_block); 625 626 let newValue = {"attach_type": select.val(), "hash": hash}; 627 let hiddenInputValue = $hiddenInputEl.val(); 628 let hiddenInputValueJson = JSON.parse('[]'); 629 if (hiddenInputValue !== '') { 630 hiddenInputValueJson = JSON.parse(hiddenInputValue); 631 } 632 hiddenInputValueJson.push(newValue); 633 $hiddenInputEl.val(JSON.stringify(hiddenInputValueJson)); 634 } 635 }); 636 }, 637 } 638 }; 639 } 640 641 if (window.isEnabledSecureUpload && window.fileserviceUploadHost) { 642 options.onUpload = function (filesToUpload, settings) { 643 var secureDirectUploadUri = '/fileservice/widget/secure-direct-upload'; 644 try { 645 var session = localStorage.getItem('session');
646 var requestParams = {"fs_ref": window.location.href}; 647 648 if (session !== undefined && session != null){ 649 var objSession = jQuery.parseJSON(session); 650 651 if (objSession.hasOwnProperty('user_id') && objSession.user_id != null) { 652 requestParams.fs_u = objSession.user_id; 653 } else { 654 requestParams.fs_u = -1; 655 } 656 } 657 658 secureDirectUploadUri += '?' + jQuery.param(requestParams); 659 } catch (err) { 660 } 661 662 $.ajax({ 663 url: '/fileservice/widget/create-secret-link', 664 method: 'GET', 665 data: { 666 host: window.fileserviceUploadHost, 667 uri: secureDirectUploadUri, 668 expires: 600 669 }, 670 success: function (data, textStatus, jqXHR) { 671 if (data.link) { 672 settings.uploadScript = data.link; 673 } 674 }, 675 error: function (http, message, exc) {sendCreateLinkError(http, message, exc);}, 676 async: false // to make it synchronous 677 }); 678 }; 679 } 680 681 initUploadify($button, options); 682 683 var $uploadifiveButton = $uploader.find('.uploadifive-button'); 684 685 var $container = $el.parents('.contains-uploadify').find('.attach-file-button-container'); 686 687 $uploadifiveButton.appendTo($container); 688 $uploadifiveButton.css('line-height', '20px'); 689 $uploadifiveButton.height('20px'); 690 $uploadifiveButton.width('15px'); 691 $uploadifiveButton.css('background', 'transparent'); 692 $uploadifiveButton.css('color', '#999'); 693 $uploadifiveButton.css('text-align', 'center'); 694 $uploadifiveButton.css('padding', '0'); 695 $uploadifiveButton.css('font-size', '1em'); 696 $el.data('uploader', $uploader); 697 698 afterCreateCallback && afterCreateCallback($el, $uploader); 699 }, 700 initTemplates: function($el) { 701 $el.find('.template-link').click( function() { 702 var id = $(this).data('template-id'); 703 704 let userId = $el.parents('.answer-content').find('a[data-user-id]').data('user-id'); 705 706 707 ajaxCall("/pl/notifications/skill-question/get-template?id=" + id, { userId: userId }, {method: "get"}, function(response) { 708 var val = $el.find('.new-comment-textarea').val(); 709 if ( val == "" ) { 710 val = response.data.answer; 711 } 712 else { 713 val = val + " " + response.data.answer; 714 } 715 $el.find('.new-comment-textarea').val( val ); 716 $el.find('.new-comment-textarea').focus(); 717 $('.new-comment-textarea', $el).trigger('keyup'); 718 $('.new-comment-textarea', $el).css('min-height', 100); 719 }) 720 }) 721 722 } 723 }; 724 725 var CommentWidget = function($comment) { 726 var that = this; 727 728 runOneTimeOnElement($comment, 'gc-comment-widget', function($el) { 729 that.init($el); 730 731 return that; 732 }); 733 }; 734 735 CommentWidget.create = function($comment) { 736 return new this($comment) 737 }; 738 739 CommentWidget.prototype = { 740 init : function($comment) { 741 this.initForms($comment); 742 this.initActions($comment); 743 this.initFilesFrontPopup($comment); 744 745 if (window.GcEmojiHelper) { 746 window.GcEmojiHelper.initEmojies($comment); 747 } 748 } 749 ,initForms : function($comment) { 750 DomHelper.findForms($comment).each(function (index, el) { 751 CommentFormWidget.create($(el)); 752 }); 753 } 754 ,initActions : function($comment) { 755 this.initActionsVisual($comment); 756 this.initEdit($comment); 757 this.initDelete($comment); 758 this.initTemplateLink($comment); 759 } 760 ,initActionsVisual : function($comment) { 761 window.eachAndRunOneTimeOnElement( 762 $comment.find('.comment-edit-link, .comment-delete-link, .comment-template-link'), 763 'comment-actions-hidden', 764 function ($el) { 765 $el.addClass('hide'); 766 return $el; 767 } 768 ); 769 window.eachAndRunOneTimeOnElement( 770 $comment.find('.comment-edit-link, .comment-delete-link, .comment-template-link'), 771 'comment-mouseout-handler', 772 function ($el) { 773 $comment.find('.comment') 774 .mouseover(function() { 775 //alert( JSON.stringify(window.userInfo) ); 776 $(this).find('.comment-edit-link').removeClass('hide'); 777 if (window.userInfo.isAdmin) { 778 $(this).find('.comment-delete-link').removeClass('hide'); 779 } 780 if(window.userInfo.isHumanDesign == "1" && $(this).find('.comment-delete-link').data( "delete" ) == "1"){ 781 $(this).find('.comment-delete-link').removeClass('hide'); 782 } 783 if ( window.userInfo.isTeacher ) { 784 $(this).find('.comment-template-link').removeClass('hide'); 785 } 786 }) 787 .mouseout(function() { 788 $(this).find('.comment-edit-link, .comment-template-link, .comment-delete-link').addClass('hide'); 789 }) 790 ; 791 return $el; 792 } 793 ); 794 } 795 ,initEdit : function($comment) { 796 window.eachAndRunOneTimeOnElement( 797 $comment.find('.comment-edit-link'), 798 'comment-edit-link-handler', 799 function ($el) { 800 $el.click(function() { 801 var $comment = $(this).parents('.comment'); 802 $comment.find('.edit-comment-active-element').removeClass('hide'); 803 $comment.find('.edit-comment-inactive-element').addClass('hide'); 804 var $textarea = $comment.find('.edit-comment-active-element textarea'); 805 $textarea.css('min-height', 50 + 'px').autosize(); 806 return false;
807 }); 808 return $el; 809 } 810 ); 811 812 window.eachAndRunOneTimeOnElement( 813 $comment.find('.comment-cancel-edit-link'), 814 'comment-cancel-edit-link-handler', 815 function ($el) { 816 $el.click(function() { 817 var $comment = $(this).parents('.comment'); 818 $comment.find('.edit-comment-active-element').addClass('hide'); 819 $comment.find('.edit-comment-inactive-element').removeClass('hide'); 820 }); 821 return $el; 822 } 823 ); 824 825 window.eachAndRunOneTimeOnElement( 826 $comment.find('.save-edited-comment-btn'), 827 'comment-save-edited-btn-handler', 828 function ($el) { 829 $el.click(function() { 830 var $btn = $(this); 831 var $commentEl = $(this).parents('.comment'); 832 var toDelete = []; 833 $commentEl.find('.delete-file-checkbox:checked').each(function(index, el) { 834 toDelete.push($(el).val()); 835 }); 836 ajaxCall($commentEl.find('.comment-edit-link').data('href'), { 837 text : $commentEl.find('.edited-comment-text').val(), 838 files_to_delete : toDelete.join(','), 839 files_to_add : $commentEl.find('.upload-value').val() 840 }, { 841 btn : $btn 842 }, function(response) { 843 $commentEl.find('.emoji-text').html($.emoji(response.html.text)); 844 var $files = $commentEl.find('.files'); 845 $files.html(response.html.files); 846 if (response.html.files.length > 0) { 847 $files.addClass('active'); 848 } 849 else { 850 $files.removeClass('active'); 851 } 852 $commentEl.find('.edit-comment-active-element').addClass('hide'); 853 $commentEl.find('.edit-comment-inactive-element').removeClass('hide'); 854 $commentEl.find('.upload-value').val(''); 855 $commentEl.find('.upload-button').uploadifive('clearQueue'); 856 $(document).trigger('gc:comment:edited'); 857 }); 858 }); 859 return $el; 860 } 861 ); 862 863 } 864 ,initDelete : function($comment) { 865 window.eachAndRunOneTimeOnElement( 866 $comment.find('.comment-delete-link'), 867 'comment-delete-link-handler', 868 function ($el) { 869 $el.click(function() { 870 var $this = $(this); 871 var id = $this.data('id'); 872 var ids = [ 873 id 874 ] 875 ,blocks = [ 876 $($this.parents('.gc-comment').get(0)) 877 ] 878 ; 879 if (confirm('ÐомменÑаÑии бÑдÑÑ ÑдаленÑ. ÐÑ ÑвеÑенÑ?')) { 880 ajaxCall('/cms/comment/delete', { 881 GetCourseCommentIds : ids 882 }, {}, function() { 883 $.each(blocks, function (index, block) { 884 DomHelper.removeCommentBlock(block); 885 }); 886 }); 887 } 888 return false; 889 }); 890 return $el; 891 } 892 ); 893 }, 894 initTemplateLink : function($comment) { 895 window.eachAndRunOneTimeOnElement( 896 $comment.find('.comment-template-link'), 897 'comment-template-link-handler', 898 function ($el) { 899 $el.click(function() { 900 var $this = $(this); 901 var id = $this.data('id'); 902 903 var questionDialog = new CommentTemplateDialog(); 904 questionDialog.open( id ); 905 906 return false; 907 }); 908 return $el; 909 } 910 ); 911 } 912 ,initFilesFrontPopup : function($comment) { 913 window.eachAndRunOneTimeOnElement( 914 $comment.find('.files a'), 915 'comment-object-front-popup-handler', 916 function ($el) { 917 var $this = $el; 918 var selector = '.' + [ 919 'gc-object-front-popup', 920 $this.data('object-id'), 921 $this.data('object-type-id') 922 ].join('-'); 923 924 var $all = $(selector); 925 var $tile = $all.filter('.gc-object-front-popup-clickable-tile'); 926 927 if ($tile.length > 0) { 928 $this.removeClass('gc-object-front-popup-clickable'); 929 $this.click(function() { 930 $tile.trigger('click'); 931 return false; 932 }); 933 } 934 return $el; 935 } 936 ); 937 } 938 }; 939 940 var TypingBlockWidget = function ($tree) { 941 var typingUsers = {}; 942 var timeouts = {}; 943 var $block = $tree.find('.typing-text'); 944 945 var refresh = function() { 946 var messages = []; 947 var lastTypingUser = null; 948 for (var i in typingUsers) { 949 lastTypingUser = typingUsers[i] 950 messages.push(typingUsers[i].user_name); 951 } 952 if (messages.length === 0) { 953 $block.html(''); 954 } 955 else { 956 var maxLen = CONSTANTS.MAX_SHOW_TYPING_USERS; 957 if (messages.length > maxLen) { 958 var len = messages.length; 959 messages = messages.slice(0, maxLen); 960 messages.push('еÑе '+(len - maxLen)) 961 } 962 963 if ( messages.length > 1 ) { 964 $block.html(messages.join(' и ')+' '+(messages.length > 1 ? 'пиÑÑÑ' : 'пиÑеÑ')); 965 } else {
966 const darkTheme = gcGetCookie('gc_inc_dark'); 967 968 if (parseInt(darkTheme)) { 969 $block.html( "<div class='comment-wrapper'> <div class='comment'>" + 970 " <div class='user-image-wrapper'> " + lastTypingUser.user_user_thumbnail + '</div>' + 971 ' <div class="text-content"><img src="/public/img/type.svg"></div>' + "</div></div>"); 972 } else { 973 $block.html( "<div class='comment-wrapper'> <div class='comment'>" + 974 " <div class='user-image-wrapper'> " + lastTypingUser.user_user_thumbnail + '</div>' + 975 ' <div class="text-content"><img src="/public/img/typing.gif"></div>' + "</div></div>"); 976 } 977 } 978 } 979 }; 980 981 this.addUser = function(userId, userName, userThumbnail) { 982 if (window.accountUserId != userId) { 983 clearTimeout(timeouts[userId]); 984 if (!typingUsers.hasOwnProperty(userId)) { 985 typingUsers[userId] = { 986 user_id : userId 987 ,user_name : userName 988 ,user_user_thumbnail : userThumbnail 989 }; 990 } 991 992 timeouts[userId] = setTimeout(function() { 993 delete typingUsers[userId]; 994 var len = 0; 995 for (var i in typingUsers) { 996 len++; 997 } 998 if (len === 0) { 999 $block.html(''); 1000 } 1001 }, CONSTANTS.TYPING_INTERVAL + 1000); 1002 } 1003 refresh(); 1004 }; 1005 1006 this.removeUser = function(userId) { 1007 delete typingUsers[userId]; 1008 clearTimeout(timeouts[userId]); 1009 refresh(); 1010 }; 1011 }; 1012 var addComment = function(objectId, objectTypeId, settings, html, isNode ) { 1013 var groupId = settings.values.group > 0 ? settings.values.group : 0; 1014 var blockClass = 'comments-' + [ 1015 settings.values.object_type_id, 1016 settings.values.object_id, 1017 groupId 1018 ].join('-'); 1019 var $commentsBlocks = $('.'+blockClass); 1020 if ( $commentsBlocks.length == 0 ) { 1021 return; 1022 } 1023 $commentsBlocks.each(function(index, el) { 1024 var $commentsBlock = $(el); 1025 var $tree = $($commentsBlock.parents('.comments-tree').get(0)); 1026 if (isNode && $tree.data('paused')) { 1027 $tree.data('queue').push({ 1028 objectId : objectId 1029 , objectTypeId : objectTypeId 1030 , settings : settings 1031 , html : html 1032 }); 1033 if ($tree.data('queue').length > CONSTANTS.MAX_COMMENTS_PER_PAGE_DIRECTION_DESC) { 1034 $tree.data('queue').shift(); 1035 } 1036 $tree.data('pause-button').find('.value').html('(' + $tree.data('queue').length + ')'); 1037 return; 1038 } 1039 var $html = $( html ); 1040 var commentId = $html.find('.comment').data('object-id'); 1041 var $commentExist = $commentsBlock.find('#comment' + commentId); 1042 if ($commentExist.length > 0) { 1043 var $commentExistFiles = $commentExist.find('.files'); 1044 var $commentNewFiles = $html.find('.files'); 1045 if ( ! $commentExistFiles.hasClass('active') && $commentNewFiles.hasClass('active') ) { 1046 $commentExistFiles.replaceWith($commentNewFiles); 1047 } 1048 return; 1049 } 1050 if (window.accountUserId == settings.accountUserId) { 1051 $html.addClass('my-comment'); 1052 } 1053 else { 1054 $html.removeClass('my-comment'); 1055 } 1056 1057 var invertOwnUser = $commentsBlock.parents('.invert-own-comment').length > 0; 1058 if ( (settings.accountUserId == settings.values.own_user_id) != invertOwnUser ) { 1059 //$html.addClass('own-user-comment'); 1060 } 1061 else { 1062 $html.removeClass('own-user-comment'); 1063 } 1064 1065 1066 TreeWidget.applyAccess(window.userInfo.isAdmin, 'admin', $html); 1067 TreeWidget.applyAccess(window.userInfo.isManager, 'manager', $html); 1068 TreeWidget.applyAccess(window.userInfo.isInAccount, 'account', $html); 1069 TreeWidget.applyAccess(window.userInfo.isTeacher, 'teacher', $html); 1070 1071 $html.find('.owner').each(function(index, el) { 1072 var $el = $(el); 1073 if($el.hasClass('admin') && window.userInfo.isAdmin) { 1074 return true; 1075 } 1076 if (!$el.hasClass('owner_'+window.accountUserId)) { 1077 $el.remove(); 1078 } 1079 }); 1080 1081 var size = CommentFormWidget.REPLY_COMMENT_HEIGHT; 1082 var isDesc = $html.data('direction') == 'desc'; 1083 if (isDesc) { 1084 1085 $commentsBlock.prepend($html); 1086 } 1087 else { 1088 $commentsBlock.append($html); 1089 } 1090 1091 if (isDesc || $tree.hasClass('more-link')) { 1092 //а todo Ñ Ð¾ÑелоÑÑ Ð±Ñ Ð²ÑводиÑÑ ÑолÑко видимÑÑ Ð¾Ð±Ð»Ð°ÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñов - динамиÑеÑкий page size и валидаÑиÑ, знаÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑÑ Ð¿ÐµÑед ÑÑим и поÑле 1093 var $commentsContainer = $($commentsBlock.parents('.comments-container').get(0)); 1094 var commentsLevel1 = $commentsContainer.find('.level-1'); 1095 var $more = $commentsContainer.find('.more'); 1096 var pageSize = settings.values.page_size; 1097 if ($more.length == 0 || $more.find('a').data('clicked') == 0) { 1098 var max = settings.values.page_size; 1099 if (commentsLevel1.length > max) { 1100 var $lastComment = commentsLevel1.get(isDesc ? commentsLevel1.length - 1 : 0); 1101 $lastComment.remove(); 1102 if ($more.length == 0) { 1103 var moreHtml = '<div class="more"> <a href="javascript:void(0);"></a>'; 1104 if (isDesc) { 1105 $commentsContainer.append(moreHtml); 1106 } 1107 else { 1108 $commentsContainer.prepend(moreHtml); 1109 } 1110 } 1111 var $a = $more.find('a'); 1112 $a.html('ÐÑе комменÑаÑии'); 1113 $a.data('page', max/pageSize); 1114 } 1115 } 1116 } 1117 1118 if (objectId != settings.values.object_id) { 1119 $commentsBlock.removeClass(blockClass); 1120 $commentsBlock.addClass('comments-' + [ 1121 settings.values.object_type_id, 1122 objectId, 1123 groupId 1124 ].join('-')); 1125 var $settingsValue = $tree.find('.settings-value'); 1126 var oldSettings = JSON.parse($settingsValue.html()); 1127 oldSettings.values.object_id = objectId; 1128 $settingsValue.html(JSON.stringify(oldSettings)); 1129 var oldTreeId = $tree.data('tree-id'); 1130 $tree.data('tree-id', [ 1131 'comments' 1132 ,objectId 1133 ,settings.values.object_type_id 1134 ,groupId ? groupId : '' 1135 ].join('-')); 1136 var widget = $tree.data('gc-comments-tree-widget'); 1137 widget.initWebSocketUserTyping( 1138 $tree, 1139 window.accountUserWebSocketConnection, 1140 oldTreeId 1141 ); 1142 widget.initWebSocketNewComments( 1143 $tree, 1144 window.accountUserWebSocketConnection, 1145 oldTreeId 1146 ); 1147 $($tree).trigger('tree:comment:created_object', [objectId, objectTypeId, settings.accountUserId]); 1148 } 1149 1150 CommentWidget.create($html); 1151 1152 $html.find('textarea').autosize().css('min-height', size + 'px'); 1153 $html.find('.new-comment-textarea').css('height', size + 'px'); 1154
1155 const darkTheme = window.gcGetCookie('gc_inc_dark'); 1156 if (parseInt(darkTheme)) { 1157 $html.find('.comment-wrapper').effect('highlight', {color: "#3a3a3a", duration: 1000 }); 1158 } else { 1159 $html.find('.comment-wrapper').effect('highlight', { duration: 1000 }); 1160 } 1161 1162 $(document).trigger('gc:comment:added'); 1163 $($tree).trigger('tree:comment:added', [ 1164 $html.find('.comment:first').data('id'), 1165 objectId, 1166 objectTypeId, 1167 settings.accountUserId, 1168 window.gcIsActiveTab 1169 ]); 1170 TreeWidget.resize($tree); 1171 }); 1172 }; 1173 1174 var commentAddAjax = function($form, data, callback, completeAjaxCallback) 1175 { 1176 ajaxCall('/cms/comment/add', data, {}, function( response ) { 1177 if (response.settings && response.html) { 1178 addComment( response.object_id, response.object_type_id, response.settings, response.html ); 1179 } 1180 var uploader, uploadButton, audioUploader; 1181 1182 if ($form) { 1183 if (!!window.presaveInLocalStorageComments) { 1184 var answerId = $('.new-comment-textarea', $form).closest('.user-answer').data('id'), 1185 localStorageKey = 'new-comment-for-answer-' + answerId; 1186 localStorage.removeItem(localStorageKey); 1187 } 1188 1189 $('.new-comment-textarea', $form).val('').css({height: '28px'}).trigger('keyup'); 1190 $('.new-comment-textarea', $form).siblings('.emoji-wysiwyg-editor').empty(); 1191 uploader = $form.parents('.new-comment').find('.comment-attach-file-link').data('uploader'); 1192 uploadButton = $form.parents('.new-comment').find('.upload-button'); 1193 1194 audioUploader = $form.parents('.new-comment').find('.audio-upload'); 1195 }
1196 if (audioUploader) { 1197 audioUploader.html(''); 1198 } 1199 1200 if ( uploader ) { 1201 uploader.find('.upload-value').val(''); 1202 } 1203 1204 if (uploadButton) { 1205 uploadButton.uploadifive('clearQueue'); 1206 } 1207 1208 // ÐÑиÑÑиÑÑ Ð²Ñе подÑказки 1209 $('.gc-comment .qna-text-element').html(''); 1210 1211 callback && callback(); 1212 }, completeAjaxCallback); 1213 }; 1214 1215 $(document).on('gc:comment:add:ajax', function(event, $form, data, callback, completeAjaxCallback) { 1216 commentAddAjax($form, data, callback, completeAjaxCallback); 1217 }); 1218 1219 $(document).on('gc:comment:submit:form', function(event, $form, callback, completeAjaxCallback) { 1220 commentAddAjax($form, $form.serialize(), callback, completeAjaxCallback); 1221 }); 1222 1223 $(document).on('gc:comment:tree:resize', function(event, $tree) { 1224 TreeWidget.resize($tree); 1225 }); 1226 1227 window.GcCommentsTreeWidget = TreeWidget; 1228 window.GcCommentWidget = CommentWidget; 1229 1230 $(document).on('change', '.change-upload-type', function () { 1231 let newType = $(this).val(); 1232 let hash = $(this).attr('attr_hash'); 1233 let $hiddenInputEl = $('input.upload-value'); 1234 let object = JSON.parse($hiddenInputEl.val()); 1235 object.forEach((item, index, array) => { 1236 if (item.hash === hash.trim()) { 1237 item.attach_type = newType; 1238 } 1239 }); 1240 $hiddenInputEl.val(JSON.stringify(object)); 1241 }); 1242 1243 if (!!window.presaveInLocalStorageComments) { 1244 $(window).on('beforeunload', function (e) { 1245 var e = e || window.event, 1246 confirm = false; 1247 1248 if ($('.answers-list').length) { 1249 $('.new-comment-textarea:focus').change(); 1250 $('.new-comment-textarea:visible').each(function () { 1251 if ($(this).val()) { 1252 confirm = true; 1253 } 1254 }); 1255 } 1256 1257 if (confirm) { 1258 e.returnValue = 'Leaving the page'; 1259 return 'Leaving the page'; 1260 } 1261 }); 1262 } 1263});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.