1 2/** 3 * Comments Module System 4 * 5 * @version 1.0.0 6 * @author William Carneiro <[email protected]> 7 * @copyright 2022 HITMO Marketing Digital 8*/ 9 10class Comments { 11 12 /** 13 * Target element 14 * 15 * @var {HTMLElement} 16 */ 17 target; 18 19 /** 20 * System settings 21 * 22 * @var {object} 23 */ 24 settings = {}; 25 26 /** 27 * Comments loaded 28 * 29 * @var {array} 30 */ 31 comments_loaded = []; 32 33 /** 34 * Comments built 35 * 36 * @var {object} 37 */ 38 comments_built = []; 39 40 /** 41 * Comments showing 42 * 43 * @var {object} 44 */ 45 comments_showing = {}; 46 47 /** 48 * Comments load attempts 49 * 50 * @var {int} 51 */ 52 comments_load_attempts = 0; 53 54 /** 55 * Comments load maximum attempts 56 * 57 * @var {int} 58 */ 59 comments_load_attempts_max = 3; 60 61 /** 62 * Initialize system 63 * 64 * @param {HTMLElement} target 65 * @param {object} settings 66 * @returns {object} 67 */ 68 constructor(target, settings = {}) { 69 const self = this; 70 71 if (!$(target)[0]) { 72 throw new Error('O elemento especificado não existe.'); 73 } 74 75 this.target = target; 76 this.settings = settings; 77 78 this.loadComments(); 79 80 $(target).find('.comments_load_more').on('click', function() { 81 self.commentsBuild(); 82 83 return false; 84 }); 85 86 $(target).find('.post_form').on('submit', function() { 87 var form = this; 88 var form_data = Object.assign(Object.fromEntries(new FormData(form)), { 89 page: settings.page, 90 referrer_type: settings.referrer.type, 91 referrer_id: settings.referrer.id 92 }); 93 94 $(this).find('textarea, button').prop('disabled', true); 95 96 $.ajax({
97 dataType: 'json', 98 method: 'POST', 99 url: setting.site_url + '/system/lib/post_comment.php', 100 context: self, 101 data: form_data, 102 success: function(data) { 103 if (data.status == 'success') { 104 this.comments_loaded.unshift(data.comment); 105 106 this.commentsBuild(data.comment.id); 107 108 $(form)[0].reset(); 109 } else { 110 alert(data.error); 111 } 112 }, 113 error: function(e) { 114 alert('(' + e.status + ') Algo deu errado ao tentar publicar seu comentário. Por favor, tente novamente.'); 115 }, 116 complete: function() { 117 $(form).find('textarea, button').prop('disabled', false); 118 } 119 }); 120 121 return false; 122 }); 123 124 return this; 125 } 126 127 /** 128 * Load comments 129 */ 130 loadComments() { 131 const self = this; 132 133 $(this.target).addClass('loading'); 134 135 $.ajax({
136 dataType: 'json', 137 method: 'POST', 138 url: setting.site_url + '/system/lib/get_comments.php', 139 context: this, 140 data: { 141 page: this.settings.page, 142 referrer_type: this.settings.referrer.type, 143 referrer_id: this.settings.referrer.id, 144 }, 145 success: function(data) { 146 this.comments_loaded = data.comments; 147 this.comments_load_attempts = 0; 148 149 if (this.settings.onLoad) { 150 this.settings.onLoad(this); 151 } 152 153 this.commentsBuild(); 154 }, 155 error: function(e) { 156 if (this.comments_load_attempts < this.comments_load_attempts_max) { 157 setTimeout(function() { 158 self.loadComments(); 159 }, 500); 160 161 this.comments_load_attempts++; 162 } else { 163 console.error('Ocorreu um erro inesperado ao tentar carregar os comentários!', e); 164 } 165 }, 166 complete: function() { 167 $(this.target).removeClass('loading'); 168 } 169 }); 170 } 171 172 /** 173 * Build comments 174 * 175 * @param {boolean} new_comment_id 176 */ 177 commentsBuild(new_comment_id = false) { 178 const self = this; 179 180 var build_count = 0; 181 182 if (!(self.target.id in this.comments_showing)) { 183 this.comments_showing[self.target.id] = []; 184 } 185 186 $.each(this.comments_loaded, function(k, comment) { 187 if (!self.comments_showing[self.target.id].includes(comment.id) && build_count < self.settings.max_results && (new_comment_id == false || new_comment_id && new_comment_id == comment.id)) { 188 var _comment = self.commentFactory(); 189 190 _comment.setId(comment.id); 191 _comment.setPage(self.settings.page); 192 _comment.setReferrerType(self.settings.referrer.type); 193 _comment.setReferrerId(self.settings.referrer.id); 194 _comment.setParentElement(self.target); 195 _comment.setAnswerStatus(comment.answer_status); 196 _comment.setDeleteStatus(comment.delete_status); 197 _comment.setPostDate(comment.date.elapsed_short); 198 _comment.setAuthor(comment.customer.shortname, (comment.customer.file_01 && comment.customer.file_01.length > 0 ? setting.site_url + '/midia/customers/' + comment.customer.file_01 : setting.site_url + '/images/i/user.svg')); 199 _comment.setMessage(comment.message); 200 201 self.comments_built.push(_comment); 202 203 $.each(comment.replies, function(rk, reply) { 204 var _reply = self.commentFactory(); 205 206 _reply.setId(reply.id); 207 _reply.setPage(self.settings.page); 208 _reply.setReferrerType(self.settings.referrer.type); 209 _reply.setReferrerId(self.settings.referrer.id); 210 _reply.setParentElement(self.target); 211 _reply.setDeleteStatus(reply.delete_status); 212 _reply.setAnswerStatus(reply.answer_status); 213 _reply.setMainComment(_comment); 214 _reply.setReplyFrom(self.getCommentById(reply.reply_from_id)); 215 _reply.setPostDate(reply.date.elapsed_short); 216 _reply.setAuthor(reply.customer.shortname, (reply.customer.file_01 && reply.customer.file_01.length > 0 ? setting.site_url + '/midia/customers/' + reply.customer.file_01 : setting.site_url + '/images/i/user.svg')); 217 _reply.setMessage(reply.message); 218 219 _comment.addReply(_reply); 220 221 self.comments_built.push(_reply); 222 }); 223 224 if (new_comment_id && comment.id == new_comment_id) { 225 $(self.target).find('.comments_list').prepend(_comment.getElement()); 226 227 setTimeout(function() { 228 self.highlightComment(_comment.getId()); 229 }, 500); 230 } else { 231 $(self.target).find('.comments_list').append(_comment.getElement()); 232 } 233 234 self.comments_showing[self.target.id].push(comment.id); 235 build_count++; 236 } 237 }); 238 239 if (this.comments_loaded.length == 0) { 240 $(self.target).addClass('no_comments_yet'); 241 } else { 242 $(self.target).removeClass('no_comments_yet'); 243 } 244 245 if (this.comments_showing[this.target.id].length < this.comments_loaded.length) { 246 $(self.target).addClass('load_more'); 247 } else { 248 $(self.target).removeClass('load_more'); 249 } 250 } 251 252 /** 253 * Get comment by ID 254 * 255 * @param {int} id 256 * @returns {object} 257 */ 258 getCommentById(id) { 259 var found_comment = null; 260 261 for (var k = 0; k < this.comments_built.length; k++) { 262 var comment = this.comments_built[k]; 263 264 if (comment.getId() == id) { 265 found_comment = comment; 266 break; 267 } 268 } 269 270 return found_comment; 271 } 272 273 /** 274 * Clear comments 275 */ 276 clearComments() { 277 $.each(this.comments_built, function(k, comment) { 278 $(comment.e).remove(); 279 }); 280 281 this.comments_built = []; 282 this.comments_loaded = []; 283 this.comments_showing = {}; 284 } 285 286 /** 287 * Highlight a comment 288 * 289 * @param {int} comment_id 290 * @param {boolean} scroll 291 */ 292 highlightComment(comment_id, scroll = false) { 293 $("[data-comment-id = '" + comment_id + "'] > .comment_container").css('background-color', 'rgb(245 182 66 / 10%)'); 294 295 setTimeout(function() { 296 $("[data-comment-id = '" + comment_id + "'] > .comment_container").css('background-color', 'transparent'); 297 }, 1000); 298 299 if (scroll) { 300 $("html, body").animate({ 301 scrollTop: $("[data-comment-id = '" + comment_id + "']").offset().top - 160 302 }, 500); 303 } 304 } 305 306 /** 307 * Show loading 308 */ 309 showLoading() { 310 $(this.target).addClass('loading'); 311 } 312 313 /** 314 * Dismiss loading 315 */ 316 dismissLoading() { 317 $(this.target).removeClass('loading'); 318 } 319 320 /** 321 * Comment Factory 322 * 323 * @returns {object} 324 */ 325 commentFactory() { 326 const self = this; 327 328 var comment = { 329 e: null, 330 parent_e: null, 331 id: null, 332 post_date: null, 333 message: null, 334 author: { 335 fullname: null, 336 picture: null 337 }, 338 page: null, 339 referrer: { 340 type: null, 341 id: null 342 }, 343 main_comment: null, 344 reply_from: null, 345 answer_status: false, 346 delete_status: false, 347 replies: [] 348 }; 349 350 comment.setId = function(id) { 351 comment.id = id; 352 }; 353 354 comment.setParentElement = function(parent_e) { 355 comment.parent_e = parent_e; 356 }; 357 358 comment.setPostDate = function(post_date) { 359 comment.post_date = post_date; 360 }; 361 362 comment.setMessage = function(message) { 363 comment.message = message; 364 }; 365 366 comment.setReplyFrom = function(reply_from) { 367 comment.reply_from = reply_from; 368 }; 369 370 comment.setMainComment = function(main_comment) { 371 comment.main_comment = main_comment; 372 }; 373 374 comment.setAnswerStatus = function(answer_status) { 375 comment.answer_status = answer_status; 376 }; 377 378 comment.setDeleteStatus = function(delete_status) { 379 comment.delete_status = delete_status; 380 }; 381 382 comment.setPage = function(page) { 383 comment.page = page; 384 }; 385 386 comment.setReferrerType = function(referrer_type) { 387 comment.referrer.type = referrer_type; 388 }; 389 390 comment.setReferrerId = function(referrer_id) { 391 comment.referrer.id = referrer_id; 392 }; 393 394 comment.addReply = function(reply) { 395 comment.replies.push(reply); 396 }; 397 398 comment.setAuthor = function(fullname, picture) { 399 comment.author.fullname = fullname; 400 comment.author.picture = picture; 401 }; 402 403 comment.getId = function() { 404 return comment.id; 405 }; 406 407 comment.getPostDate = function() { 408 return comment.post_date; 409 }; 410 411 comment.getMessage = function() { 412 return comment.message; 413 }; 414 415 comment.getDeleteStatus = function() { 416 return comment.delete_status; 417 }; 418 419 comment.getAnswerStatus = function() { 420 return comment.answer_status; 421 }; 422 423 comment.getReplies = function() { 424 return comment.replies; 425 }; 426 427 comment.getReplyFrom = function() { 428 return comment.reply_from; 429 }; 430 431 comment.getAuthorFullname = function() { 432 return comment.author.fullname; 433 }; 434 435 comment.getMainComment = function() { 436 return comment.main_comment ?? comment; 437 }; 438 439 comment.getPage = function() { 440 return comment.page; 441 }; 442 443 comment.getParentElement = function() { 444 return comment.parent_e; 445 }; 446 447 comment.getReferrerType = function() { 448 return comment.referrer.type; 449 }; 450 451 comment.getReferrerId = function() { 452 return comment.referrer.id; 453 }; 454 455 comment.rebuildElement = function() { 456 $(comment.e).replaceWith(comment.getElement()); 457 } 458 459 comment.getElement = function() { 460 let element = document.createElement('div');
461 let element_container = document.createElement('div'); 462 let author_picture = document.createElement('div'); 463 let author_picture_picture = document.createElement('div'); 464 let comment_data = document.createElement('div'); 465 let comment_data_header = document.createElement('div'); 466 let comment_data_header_info_user_name = document.createElement('div'); 467 let comment_data_header_info_post_date = document.createElement('div'); 468 let comment_data_body = document.createElement('div'); 469 let comment_data_footer = document.createElement('div'); 470 let comment_data_footer_actions = document.createElement('div'); 471 let comment_data_footer_actions_reply_from = document.createElement('div'); 472 let comment_data_footer_actions_reply_from_a = document.createElement('a'); 473 let comment_data_footer_actions_answer = document.createElement('a'); 474 let comment_data_footer_actions_answer_icon = document.createElement('i'); 475 let comment_data_footer_actions_report = document.createElement('a'); 476 let comment_data_footer_actions_report_icon = document.createElement('i'); 477 let comment_data_footer_actions_delete = document.createElement('a'); 478 let comment_data_footer_actions_delete_icon = document.createElement('i'); 479 let comment_data_footer_replies = document.createElement('div'); 480 let comment_data_footer_replies_post_reply = document.createElement('div'); 481 let comment_data_footer_replies_post_reply_reply_to = document.createElement('div'); 482 let comment_data_footer_replies_post_reply_reply_to_label = document.createElement('label'); 483 let comment_data_footer_replies_post_reply_reply_form = document.createElement('form'); 484 let comment_data_footer_replies_post_reply_reply_form_textarea = document.createElement('textarea'); 485 let comment_data_footer_replies_post_reply_reply_form_main_id = document.createElement('input'); 486 let comment_data_footer_replies_post_reply_reply_form_from_id = document.createElement('input'); 487 let comment_data_footer_replies_post_reply_reply_form_button = document.createElement('button'); 488 let comment_data_footer_replies_post_reply_reply_form_button_i = document.createElement('i'); 489 let comment_data_footer_replies_list = document.createElement('div'); 490 491 $(author_picture).addClass('author_picture'); 492 $(author_picture_picture).addClass('picture'); 493 $(author_picture_picture).css('background-image', 'url(' + (comment.author.picture ? comment.author.picture : '') + ')'); 494 $(author_picture).append(author_picture_picture); 495 496 $(comment_data_header).addClass('data_header'); 497 $(comment_data_header_info_user_name).addClass('info user_name'); 498 $(comment_data_header_info_user_name).text(comment.author.fullname); 499 $(comment_data_header_info_post_date).addClass('info post_date'); 500 $(comment_data_header_info_post_date).text(comment.getPostDate()); 501 $(comment_data_body).addClass('data_body'); 502 $(comment_data_body).text(comment.getMessage()); 503 $(comment_data_footer).addClass('data_footer'); 504 $(comment_data_footer_actions).addClass('actions'); 505 $(comment_data_footer_actions_reply_from).addClass('reply_from'); 506 $(comment_data_footer_replies).addClass('replies'); 507 $(comment_data_footer_replies_post_reply).addClass('post_reply'); 508 $(comment_data_footer_replies_post_reply_reply_to).addClass('reply_to'); 509 $(comment_data_footer_replies_post_reply_reply_form).addClass('reply_form'); 510 $(comment_data_footer_replies_post_reply_reply_form).attr('method', 'POST'); 511 $(comment_data_footer_replies_post_reply_reply_form_textarea).addClass('form-control'); 512 $(comment_data_footer_replies_post_reply_reply_form_button).addClass('btn btn-primary'); 513 $(comment_data_footer_replies_post_reply_reply_form_button_i).addClass('fa fa-reply'); 514 $(comment_data_footer_replies_list).addClass('replies_list'); 515 516 $(comment_data_footer_replies_post_reply_reply_form_textarea).attr({ 517 name: 'message', 518 minlength: 3, 519 maxlength: 1000, 520 required: true, 521 placeholder: 'Digite sua resposta...' 522 }); 523 524 $(comment_data_footer_replies_post_reply_reply_form_main_id).attr({ 525 type: 'hidden', 526 name: 'main_comment_id' 527 }); 528 529 $(comment_data_footer_replies_post_reply_reply_form_from_id).attr({ 530 type: 'hidden', 531 name: 'reply_from_id' 532 }); 533 534 $(comment_data_header).append(comment_data_header_info_user_name); 535 $(comment_data_header).append(comment_data_header_info_post_date); 536 537 if (comment.reply_from) { 538 $(comment_data_footer_actions_reply_from_a).text(comment.reply_from.getAuthorFullname()); 539 $(comment_data_footer_actions_reply_from_a).attr('href', '#') 540 541 $(comment_data_footer_actions_reply_from_a).on('click', function() { 542 self.highlightComment(comment.reply_from.getId(), true); 543 544 return false; 545 }); 546 547 $(comment_data_footer_actions_reply_from).append('Em resposta a '); 548 $(comment_data_footer_actions_reply_from).append(comment_data_footer_actions_reply_from_a); 549 550 $(comment_data_footer_actions).append(comment_data_footer_actions_reply_from); 551 } 552 553 $(comment_data_footer_actions_answer_icon).addClass('fa fa-reply me-2'); 554 $(comment_data_footer_actions_report_icon).addClass('fa fa-flag me-2'); 555 $(comment_data_footer_actions_delete_icon).addClass('fa fa-tras
555h-alt me-2'); 556 557 $(comment_data_footer_actions_answer).attr('href', '#'); 558 $(comment_data_footer_actions_report).attr('href', '#'); 559 $(comment_data_footer_actions_delete).attr('href', '#'); 560 561 $(comment_data_footer_actions_answer).append(comment_data_footer_actions_answer_icon).append('Responder'); 562 $(comment_data_footer_actions_report).append(comment_data_footer_actions_report_icon).append('Denunciar'); 563 $(comment_data_footer_actions_delete).append(comment_data_footer_actions_delete_icon).append('Apagar'); 564 565 $(comment_data_footer_actions_answer).on('click', function() { 566 if (!comment.getAnswerStatus()) { 567 if (confirm('Este recurso está disponÃvel apenas para Assinantes!\nAssine agora para responder este comentário com benefÃcios exclusivos!\n\nDesejar ver nossos planos agora?')) { 568 location.href = setting.site_url + '/assine/'; 569 } 570 571 return false; 572 } 573 574 let main_comment = comment.getMainComment(); 575 576 if ($(main_comment.e).find(".post_reply .reply_form [name = 'reply_from_id']").val() != comment.getId()) { 577 if ($(main_comment.e).find('.post_reply .reply_form textarea').val().length > 0) { 578 if (!confirm('Você começou a escrever uma resposta para outro comentário desta conversa. Se prosseguir, seu texto será perdido.\n\nDeseja continuar?')) { 579 return false; 580 } 581 } 582 } else { 583 $(main_comment.e).find('.post_reply .reply_form textarea')[0].focus(); 584 585 return false; 586 } 587 588 $(main_comment.e).find(".post_reply .reply_form [name = 'reply_from_id']").val(comment.getId()); 589 $(main_comment.e).find(".post_reply .reply_form [name = 'main_comment_id']").val(comment.getMainComment().getId()); 590 591 $(main_comment.e).addClass('reply'); 592 $(main_comment.e).find('.post_reply .reply_to').empty(); 593 594 if (comment.getId() != main_comment.getId()) { 595 var answer_to_a = document.createElement('a'); 596 597 $(answer_to_a).attr('href', '#'); 598 599 $(answer_to_a).on('click', function() { 600 self.highlightComment(comment.getId(), true); 601 602 return false; 603 }); 604 605 $(answer_to_a).text(comment.author.fullname); 606 607 $(main_comment.e).find('.post_reply .reply_to').append('Em resposta a ').append(answer_to_a); 608 } 609 610 $(main_comment.e).find('.post_reply .reply_form textarea').val(''); 611 $(main_comment.e).find('.post_reply .reply_form textarea')[0].focus(); 612 613 return false; 614 }); 615 616 $(comment_data_footer_actions_delete).on('click', function() { 617 if (confirm('Tem certeza que desejar apagar o seu comentário?')) { 618 self.clearComments(); 619 self.showLoading(); 620 621 $.ajax({
622 dataType: 'json', 623 method: 'POST', 624 url: setting.site_url + '/system/lib/delete_comment.php', 625 data: { 626 id: comment.getId() 627 }, 628 context: self, 629 success: function(data) { 630 if (data.status == 'success') { 631 alert('Seu comentário foi deletado!'); 632 } else { 633 alert(data.error); 634 } 635 }, 636 error: function(e) { 637 alert('(' + e.status + ') Algo deu errado ao tentar deletar seu comentário. Por favor, tente novamente.'); 638 }, 639 complete: function() { 640 self.loadComments(); 641 } 642 }); 643 } 644 645 return false; 646 }); 647 648 $(comment_data_footer_actions).append(comment_data_footer_actions_answer); 649 // $(comment_data_footer_actions).append(comment_data_footer_actions_report); 650 651 if (comment.getDeleteStatus()) { 652 $(comment_data_footer_actions).append(comment_data_footer_actions_delete); 653 } 654 655 $.each(comment.getReplies(), function(k, reply) { 656 $(comment_data_footer_replies_list).append(reply.getElement()); 657 }); 658 659 $(comment_data_footer_replies_post_reply_reply_to).append(comment_data_footer_replies_post_reply_reply_to_label); 660 661 $(comment_data_footer_replies_post_reply_reply_form_button).append(comment_data_footer_replies_post_reply_reply_form_button_i); 662 663 $(comment_data_footer_replies_post_reply_reply_form).append(comment_data_footer_replies_post_reply_reply_form_textarea); 664 $(comment_data_footer_replies_post_reply_reply_form).append(comment_data_footer_replies_post_reply_reply_form_button); 665 $(comment_data_footer_replies_post_reply_reply_form).append(comment_data_footer_replies_post_reply_reply_form_from_id); 666 $(comment_data_footer_replies_post_reply_reply_form).append(comment_data_footer_replies_post_reply_reply_form_main_id); 667 668 $(comment_data_footer_replies_post_reply_reply_form).on('submit', function() { 669 let main_comment = comment.getMainComment(); 670 671 var form = this; 672 var form_data = Object.assign(Object.fromEntries(new FormData(form)), { 673 page: main_comment.getPage(), 674 referrer_type: main_comment.getReferrerType(), 675 referrer_id: main_comment.getReferrerId() 676 }); 677 678 $(this).find('textarea, button').prop('disabled', true); 679 680 $.ajax({
681 dataType: 'json', 682 method: 'POST', 683 url: setting.site_url + '/system/lib/post_comment.php', 684 data: form_data, 685 context: self, 686 success: function(data) { 687 if (data.status == 'success') { 688 var reply = this.commentFactory(); 689 690 reply.setId(data.comment.id); 691 reply.setPage(comment.getPage()); 692 reply.setReferrerType(comment.getReferrerType()); 693 reply.setReferrerId(comment.getReferrerId()); 694 reply.setParentElement(comment.getParentElement()); 695 reply.setAnswerStatus(data.comment.answer_status); 696 reply.setDeleteStatus(data.comment.delete_status); 697 reply.setMainComment(comment.getMainComment()); 698 reply.setReplyFrom(this.getCommentById(data.comment.reply_from_id)); 699 reply.setPostDate(data.comment.date.elapsed_short); 700 reply.setAuthor(data.comment.customer.shortname, (data.comment.customer.file_01 && data.comment.customer.file_01.length > 0 ? setting.site_url + '/midia/customers/' + data.comment.customer.file_01 : setting.site_url + '/images/i/user.svg')); 701 reply.setMessage(data.comment.message); 702 703 comment.addReply(reply); 704 comment.rebuildElement(); 705 706 setTimeout(function() { 707 self.highlightComment(reply.getId()); 708 }, 500); 709 710 this.comments_built.push(reply); 711 712 $(form)[0].reset(); 713 } else { 714 alert(data.error); 715 } 716 }, 717 error: function(e) { 718 alert('(' + e.status + ') Algo deu errado ao tentar publicar seu comentário. Por favor, tente novamente.'); 719 }, 720 complete: function() { 721 $(form).find('textarea, button').prop('disabled', false); 722 } 723 }); 724 725 return false; 726 }); 727 728 $(comment_data_footer_replies_post_reply).append(comment_data_footer_replies_post_reply_reply_to); 729 $(comment_data_footer_replies_post_reply).append(comment_data_footer_replies_post_reply_reply_form); 730 731 $(comment_data_footer_replies).append(comment_data_footer_replies_list); 732 $(comment_data_footer_replies).append(comment_data_footer_replies_post_reply); 733 734 $(comment_data_footer).append(comment_data_footer_actions); 735 736 if (comment.getId() == comment.getMainComment().getId()) { 737 $(comment_data_footer).append(comment_data_footer_replies); 738 } 739 740 $(comment_data).addClass('comment_data'); 741 $(comment_data).append(comment_data_header); 742 $(comment_data).append(comment_data_body); 743 $(comment_data).append(comment_data_footer); 744 745 $(element_container).addClass('comment_container'); 746 $(element_container).append(author_picture); 747 $(element_container).append(comment_data); 748 749 $(element).attr('data-comment-id', comment.getId()); 750 $(element).addClass('comment'); 751 $(element).append(element_container); 752 753 comment.e = element; 754 755 return comment.e; 756 } 757 758 return comment; 759 } 760 761}
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.