1/** 2 * JCOMMENT 3 * 4 * @version Joomla! 5 * @package JCOMMENT 6 * @author Joomla! Extensions Store 7 * @copyright (C) 2021 Joomla! Extensions Store 8 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html 9 */ 10//'use strict'; 11function JCommentEvents() {} 12 13function JCommentInput() {} 14 15function JCommentIndicator() { 16 this.init(); 17} 18 19function JCommentForm(id, editor) { 20 this.init(id, editor); 21} 22 23function JCommentEditor(textarea, resizable) { 24 this.init(textarea, resizable); 25} 26 27function JComment(oi, og, r) { 28 this.init(oi, og, r); 29} 30 31JCommentEvents.prototype = { 32 add: function(o, e, f) { 33 if (o.addEventListener) { 34 o.addEventListener(e, f, false); 35 return true; 36 } else if (o.attachEvent) { 37 return o.attachEvent("on" + e, f); 38 } else { 39 return false; 40 } 41 }, 42 remove: function(o, e, f) { 43 if (o.removeEventListener) { 44 o.removeEventListener(e, f, false); 45 } else if (o.detachEvent) { 46 o.detachEvent("on" + e, o[e + f]); 47 o[e + f] = null; 48 o["e" + e + f] = null; 49 } 50 }, 51 cancel: function(e) { 52 if (e.stopPropagation) { 53 e.cancelBubble = true; 54 e.preventDefault(); 55 e.stopPropagation(); 56 } 57 e.returnValue = false; 58 return false; 59 }, 60 target: function(e) { 61 var t; 62 if (!e) e = window.event; 63 if (e.target) t = e.target; 64 else if (e.srcElement) t = e.srcElement; 65 if (t.nodeType == 3) t = t.parentNode; 66 return t; 67 } 68}; 69 70JCommentInput.prototype = { 71 register: function(el) { 72 if (el) { 73 var th = this, 74 events = new JCommentEvents(); 75 events.add(el, 'focus', function(e) { 76 return th.onFocus(e); 77 }); 78 events.add(el, 'blur', function(e) { 79 return th.onBlur(e); 80 }); 81 } 82 }, 83 unregister: function(el) { 84 if (el) { 85 var th = this, 86 events = new JCommentEvents(); 87 events.remove(el, 'focus', function(e) { 88 return th.onFocus(e); 89 }); 90 events.remove(el, 'blur', function(e) { 91 return th.onBlur(e); 92 }); 93 } 94 }, 95 onFocus: function(e) { 96 var t = JCommentEvents.prototype.target(e); 97 if (t != null) { 98 t.className = t.className.replace('error', '') + ' selected'; 99 } 100 }, 101 onBlur: function(e) { 102 var t = JCommentEvents.prototype.target(e); 103 if (t != null) { 104 var c = t.className.replace('error', ''); 105 c = c.replace('error', ''); 106 c = c.replace('selected', ''); 107 t.className = c.replace(/^\s+/g, ""); 108 } 109 } 110}; 111 112JCommentEditor.prototype = { 113 ta: null, 114 l10n: {}, 115 tags: {}, 116 smiles: {}, 117 events: null, 118 counter: null, 119 focused: false, 120 resizable: true, 121 122 init: function(textareaID, r) { 123 this.ta = JComment.prototype.$(textareaID); 124 this.l10n = { 125 counterPre: '', 126 counterPost: ' symbols left' 127 }; 128 this.resizable = r; 129 this.events = new JCommentEvents(); 130 this.defaultHeight = this.ta.clientHeight; 131 this.defaultRows = this.ta.rows; 132 if (this.resizable) { 133 this.addGrippie(); 134 } 135 136 var th = this; 137 this.events.add(document, !window.opera && document.all ? 'keydown' : 'keypress', function(e) { 138 return th.onKeyPress(e); 139 }); 140 this.events.add(this.ta, 'click', function(e) { 141 th.closeSmiles(); 142 return th.storeCaret(this.ta); 143 }); 144 this.events.add(this.ta, 'select', function(e) { 145 return th.storeCaret(this.ta); 146 }); 147 this.events.add(this.ta, 'change', function(e) { 148 th.onChange(); 149 return th.storeCaret(this.ta); 150 }); 151 this.events.add(this.ta, 'keyup', function(e) { 152 return th.onChange(); 153 }); 154 this.events.add(this.ta, 'focus', function(e) { 155 th.closeSmiles(); 156 return th.focused = true; 157 }); 158 this.events.add(this.ta, 'blur', function(e) { 159 return th.focused = false; 160 }); 161 }, 162 onKeyPress: function(e) { 163 if (!this.focused) { 164 return; 165 } 166 var k = String.fromCharCode(e.keyCode ? e.keyCode : e.charCode), 167 t; 168 for (var id in this.tags) { 169 t = this.tags[id]; 170 if (!t.key || k.toUpperCase() != t.key.toUpperCase()) continue; 171 if (t.ctrl && !e[t.ctrl + "Key"]) continue; 172 this.insertTag(id); 173 return this.events.cancel(e); 174 } 175 return e.returnValue; 176 }, 177 defined: function(v) { 178 return (typeof(v) != "undefined"); 179 }, 180 clear: function() { 181 this.ta.value = ''; 182 if (this.defaultHeight) { 183 this.ta.style.height = this.defaultHeight + 'px'; 184 } 185 this.updateCounter(); 186 }, 187 focus: function() { 188 this.ta.focus(); 189 }, 190 storeCaret: function() { 191 var ta = this.ta; 192 if (ta.createTextRange) ta.caretPos = document.selection.createRange().duplicate(); 193 }, 194 getElementPos: function(e) { 195 var p = { 196 left: 0, 197 top: 0, 198 right: 0, 199 bottom: 0 200 }; 201 while (e != null) { 202 p.left += e.offsetLeft; 203 p.top += e.offsetTop; 204 e = e.offsetParent; 205 } 206 p.right += p.left; 207 p.bottom += p.top; 208 return p; 209 }, 210 getSelection: function() { 211 var ta = this.ta, 212 s = ''; 213 if (document.selection && document.selection.createRange) { 214 s = document.selection.createRange().text; 215 } else { 216 s = ta.value.substr(ta.selectionStart, ta.selectionEnd - ta.selectionStart); 217 } 218 return s; 219 }, 220 insertText: function(text) { 221 var ta = this.ta; 222 if (this.defined(ta.caretPos) && ta.createTextRange) { 223 ta.focus(); 224 var sel = document.selection.createRange(); 225 sel.text = sel.text + text; 226 ta.focus(); 227 } else if (this.defined(ta.selectionStart)) { 228 var ss = ta.value.substr(0, ta.selectionStart); 229 var se = ta.value.substr(ta.selectionEnd), 230 sp = ta.scrollTop; 231 ta.value = ss + text + se; 232 if (ta.setSelectionRange) { 233 ta.focus(); 234 ta.setSelectionRange(ss.length + text.length, ss.length + text.length); 235 } 236 ta.scrollTop = sp; 237 } else { 238 ta.value += text; 239 ta.focus(ta.value.length - 1); 240 } 241 }, 242 surroundText: function(t1, t2) { 243 var ta = this.ta; 244 if (this.defined(ta.caretPos) && ta.createTextRange) { 245 var cp = ta.caretPos, 246 tl = cp.text.length; 247 cp.text = cp.text.charAt(cp.text.length - 1) == ' ' ? t1 + cp.text + t2 + ' ' : t1 + cp.text + t2; 248 if (tl == 0) { 249 cp.moveStart("character", -t2.length); 250 cp.moveEnd("character", -t2.length); 251 cp.select(); 252 } else { 253 ta.focus(cp); 254 } 255 } else if (this.defined(ta.selectionStart)) { 256 var ss = ta.value.substr(0, ta.selectionStart), 257 se = ta.value.substr(ta.selectionEnd); 258 var sl = ta.value.substr(ta.selectionStart, ta.selectionEnd - ta.selectionStart); 259 var nc = ta.selectionStart, 260 sp = ta.scrollTop; 261 ta.value = ss + t1 + sl + t2 + se; 262 if (ta.setSelectionRange) { 263 if (sl.length == 0) { 264 ta.setSelectionRange(nc + t1.length, nc + t1.length); 265 } else { 266 ta.setSelectionRange(nc, nc + t1.length + sl.length + t2.length); 267 } 268 ta.focus(); 269 } 270 ta.scrollTop = sp; 271 } else { 272 ta.value += t1 + t2; 273 ta.focus(ta.value.length - 1); 274 } 275 }, 276 insertTag: function(id) { 277 var tag = this.tags[id]; 278 if (!tag) return;
279 var s = this.getSelection(); 280 if (s.length > 0) { 281 this.surroundText(tag.open, tag.close); 282 } 283 }, 284 initTags: function() { 285 if (this.bbc == null || this.bbc.length == 0) { 286 this.bbc = {}; 287 this.bbc['b'] = { 288 id: 'bbcode-b', 289 open: '[b]', 290 close: '[/b]', 291 key: 'B', 292 ctrl: 'ctrl', 293 hint: 'Bold' 294 }; 295 this.bbc['i'] = { 296 id: 'bbcode-i', 297 open: '[i]', 298 close: '[/i]', 299 key: 'I', 300 ctrl: 'ctrl', 301 hint: 'Italic' 302 }; 303 this.bbc['u'] = { 304 id: 'bbcode-u', 305 open: '[u]', 306 close: '[/u]', 307 key: 'U', 308 ctrl: 'ctrl', 309 hint: 'Underline' 310 }; 311 this.bbc['s'] = { 312 id: 'bbcode-s', 313 open: '[s]', 314 close: '[/s]', 315 key: null, 316 ctrl: null, 317 hint: 'Strikeout' 318 }; 319 this.bbc['img'] = { 320 id: 'bbcode-img', 321 open: '[img]', 322 close: '[/img]', 323 key: null, 324 ctrl: null, 325 hint: 'Image' 326 }; 327 this.bbc['uploadimg'] = { 328 id: 'bbcode-uploadimg', 329 open: '[uploadimg]', 330 close: '[/uploadimg]', 331 key: null, 332 ctrl: null, 333 hint: 'Image' 334 }; 335 this.bbc['file'] = { 336 id: 'bbcode-file', 337 open: '[file]', 338 close: '[/file]', 339 key: null, 340 ctrl: null, 341 hint: 'File' 342 }; 343 this.bbc['url'] = { 344 id: 'bbcode-url', 345 open: '[url]', 346 close: '[/url]', 347 key: null, 348 ctrl: null, 349 hint: 'Link' 350 }; 351 this.bbc['hide'] = { 352 id: 'bbcode-hide', 353 open: '[hide]', 354 close: '[/hide]', 355 key: null, 356 ctrl: null, 357 hint: 'Hidden' 358 }; 359 this.bbc['quote'] = { 360 id: 'bbcode-quote', 361 open: '[quote]', 362 close: '[/quote]', 363 key: null, 364 ctrl: null, 365 hint: 'Quote' 366 }; 367 this.bbc['list'] = { 368 id: 'bbcode-list', 369 open: '[list][*]', 370 close: '[/list]', 371 key: null, 372 ctrl: null, 373 hint: 'List' 374 }; 375 } 376 }, 377 378 createButton: function(i, t, c, f, img) { 379 var e; 380 if (img == null || img == "") { 381 e = document.createElement('a'); 382 e.style.display = 'block'; 383 e.setAttribute('href', 'javascript:void(0)'); 384 } else { 385 e = document.createElement('img'); 386 if (t) { 387 e.setAttribute('alt', t); 388 } 389 e.setAttribute('src', img); 390 if (!c) { 391 c = 'custombbcode'; 392 } 393 } 394 if (i) { 395 e.setAttribute('id', i); 396 } 397 if (t) { 398 e.setAttribute('title', t); 399 } 400 if (c) { 401 e.className = c; 402 } 403 var ee = e; 404 e.onclick = (f != null ? function() { 405 f(ee); 406 return false; 407 } : function() { 408 return false; 409 }); 410 return e; 411 }, 412 413 addButton: function(id, h, p, ot, ct, css, img) { 414 if (this.ta) { 415 this.initTags(); 416 var tag = this.bbc[id], 417 th = this; 418 if (!tag) { 419 if (ot && ct) { 420 this.bbc[id] = { 421 id: id, 422 open: ot, 423 close: ct, 424 key: null, 425 ctrl: null, 426 hint: h 427 }; 428 tag = this.bbc[id]; 429 } else { 430 return; 431 } 432 } 433 if (this.bbcPanel == null) { 434 this.bbcPanel = document.createElement('span'); 435 this.bbcPanel.className = 'bbcode'; 436 this.bbcPanel.style.display = 'block'; 437 this.ta.parentNode.insertBefore(this.bbcPanel, this.ta); 438 } 439 var f = function() { 440 var s = th.getSelection(); 441 if (s.length > 0) { 442 th.surroundText(tag.open, tag.close); 443 } else { 444 var v = prompt(p, ''); 445 if (null != v && '' != v) { 446 th.insertText(tag.open + v + tag.close); 447 } 448 } 449 return false; 450 }; 451 452 var textareaReference = this.ta; 453 var uploadImgFunction = function(button) { 454 var imageFormField = document.querySelector('#imagecomment'); 455 var spanArrow = document.querySelector('#imagecommentarrow'); 456 if(imageFormField) { 457 imageFormField.remove(); 458 spanArrow.remove(); 459 } else { 460 var imgInputField = document.createElement('input'); 461 imgInputField.id = 'imagecomment'; 462 imgInputField.name = 'imagecomment'; 463 imgInputField.type = 'file'; 464 document.querySelector('span.bbcode').insertBefore(imgInputField, this.ta); 465 466 var arrowSpan = document.createElement('div'); 467 arrowSpan.id = 'imagecommentarrow'; 468 arrowSpan.classList.add('jcomment-arrow-popover'); 469 arrowSpan.classList.add('jcomment-arrow-popover-fileinput'); 470 document.querySelector('span.bbcode').insertBefore(arrowSpan, this.ta); 471 472 imgInputField.style.left = `${button.offsetLeft - 48}px`; 473 arrowSpan.style.left = `${button.offsetLeft + 12}px`; 474 475 // Rileva se il dispositivo è touch (mobile/tablet) 476 var isTouchDevice = ( 477 'ontouchstart' in window || 478 navigator.maxTouchPoints > 0 || 479 navigator.msMaxTouchPoints > 0 480 ); 481 482 if (isTouchDevice) { 483 imgInputField.click(); 484 } 485 } 486 } 487 var uploadFileFunction = function(button) { 488 var fileFormField = document.querySelector('#filecomment'); 489 var spanArrow = document.querySelector('#filecommentarrow'); 490 if(fileFormField) { 491 fileFormField.remove(); 492 spanArrow.remove(); 493 } else { 494 var fileInputField = document.createElement('input'); 495 fileInputField.id = 'filecomment'; 496 fileInputField.name = 'filecomment'; 497 fileInputField.type = 'file'; 498 document.querySelector('span.bbcode').insertBefore(fileInputField, this.ta); 499 500 var arrowSpan = document.createElement('div'); 501 arrowSpan.id = 'filecommentarrow'; 502 arrowSpan.classList.add('jcomment-arrow-popover'); 503 arrowSpan.classList.add('jcomment-arrow-popover-fileinput'); 504 document.querySelector('span.bbcode').insertBefore(arrowSpan, this.ta); 505 506 fileInputField.style.left = `${button.offsetLeft - 48}px`; 507 arrowSpan.style.left = `${button.offsetLeft + 12}px`; 508 } 509 } 510 if(id != 'uploadimg') { 511 if(id == 'file') { 512 tag.e = this.createButton(tag.id, (h != null ? h : tag.hint), (css ? css : tag.id), uploadFileFunction, img); 513 } else { 514 tag.e = this.createButton(tag.id, (h != null ? h : tag.hint), (css ? css : tag.id), f, img); 515 } 516 } else { 517 tag.e = this.createButton(tag.id, (h != null ? h : tag.hint), (css ? css : tag.id), uploadImgFunction, img); 518 } 519 this.bbcPanel.appendChild(tag.e); 520 this.tags[tag.id] = tag; 521 } 522 }, 523 524 initSmiles: function() { 525 if (this.ta) { 526 this.smilesPanel = document.createElement('div'); 527 if (this.bbcPanel) { 528 document.body.appendChild(this.smilesPanel);
529 this.smilesPanel.id = 'comments-form-smilespanel'; 530 this.smilesPanel.setAttribute('class', 'comment-form-close'); 531 var jc = this, 532 f = function(e) { 533 var sp = jc.smilesPanel, 534 p = jc.getElementPos(e); 535 if (sp) { 536 sp.className = (sp.className == '' || sp.className == 'comment-form-close' ? 'comment-form-open' : 'comment-form-close'); 537 var sps = sp.style; 538 sps.left = p.left + "px"; 539 sps.top = p.bottom + e.offsetHeight + "px"; 540 sps.zIndex = 99; 541 } 542 return false; 543 }; 544 this.bbcPanel.appendChild(this.createButton(null, 'Emojis', 'bbcode-smile', f)); 545 } else { 546 this.smilesPanel.className = 'smiles'; 547 this.ta.parentNode.insertBefore(this.smilesPanel, this.ta); 548 } 549 } 550 }, 551 closeSmiles: function() { 552 if (this.smilesPanel && this.bbcPanel) { 553 this.smilesPanel.setAttribute('class', 'comment-form-close'); 554 } 555 }, 556 557 addSmile: function(code, image) { 558 if (this.ta) { 559 if (!this.smilesPanel) { 560 return; 561 } 562 var th = this, 563 e = document.createElement('img'); 564 565 function imageExists(image_url){ 566 var http = new XMLHttpRequest(); 567 http.open('HEAD', image_url, false); 568 http.send(); 569 return http.status != 404; 570 } 571 e.setAttribute('src', image); 572 e.setAttribute('alt', code); 573 e.setAttribute('title', code); 574 e.className = 'smile'; 575 e.onclick = function() { 576 th.insertText(' ' + code + ' '); 577 }; 578 this.smilesPanel.appendChild(e); 579 } 580 }, 581 initEmojis: function() { 582 if (this.ta) { 583 this.emojisPanel = document.createElement('div'); 584 this.emojisPanel.id = 'comments-form-emojispanel'; 585 this.emojisPanel.setAttribute('class', 'comment-form-close'); 586 this.emojisPanel.style.maxHeight = '300px'; 587 this.emojisPanel.style.overflowY = 'auto'; 588 589 if (this.bbcPanel) { 590 document.body.appendChild(this.emojisPanel); 591 var jc = this, 592 f = function(e) { 593 var ep = jc.emojisPanel, 594 p = jc.getElementPos(e); 595 if (ep) { 596 ep.className = (ep.className === '' || ep.className === 'comment-form-close') ? 'comment-form-open' : 'comment-form-close'; 597 var eps = ep.style; 598 eps.left = p.left + "px"; 599 eps.top = p.bottom + e.offsetHeight + "px"; 600 eps.zIndex = 99; 601 } 602 return false; 603 }; 604 this.bbcPanel.appendChild(this.createButton(null, 'Unicode emojis', 'bbcode-emoji', f)); 605 } else { 606 this.emojisPanel.className = 'emojis'; 607 this.ta.parentNode.insertBefore(this.emojisPanel, this.ta); 608 } 609 610 } 611 }, 612 addEmojiCategory: function(label) { 613 if (!this.emojisPanel) return; 614 615 var title = document.createElement('div'); 616 title.className = 'emoji-category-title'; 617 title.textContent = label; 618 this.emojisPanel.appendChild(title); 619 }, 620 addEmoji: function(char, title) { 621 if (this.ta) { 622 if (!this.emojisPanel) return; 623 624 var th = this, 625 e = document.createElement('span'); 626 627 var textarea = this.ta; 628 e.textContent = char; 629 e.setAttribute('title', title); 630 e.className = 'emoji-item'; 631 e.style.cursor = 'pointer'; 632 e.style.fontSize = '20px'; 633 e.style.padding = '2px'; 634 e.onclick = function() { 635 th.insertText(char); 636 textarea.dispatchEvent(new Event('input', { 637 bubbles: true, 638 cancelable: true 639 })); 640 }; 641 642 this.emojisPanel.appendChild(e); 643 } 644 }, 645 closeEmojis: function() { 646 if (this.emojisPanel && this.bbcPanel) { 647 this.emojisPanel.setAttribute('class', 'comment-form-close'); 648 } 649 },
650 initBackgrounds: function () { 651 // Manage styles apply syncronously to server side loaded messages into HTML 652 if(typeof(window.jcommentStyleMap) !== 'undefined') { 653 const styleMap = window.jcommentStyleMap || {}; 654 const comments = document.querySelectorAll('.comment-body[data-style]'); 655 656 comments.forEach(comment => { 657 const styleKey = comment.getAttribute('data-style'); 658 const styleDef = styleMap[styleKey]; 659 660 if (styleDef) { 661 if (styleDef.style.includes('linear-gradient') || styleDef.style.includes('radial-gradient')) { 662 const gradientMatch = styleDef.style.match(/(linear|radial)-gradient\([^;]+?\)/i); 663 if (gradientMatch) { 664 comment.style.backgroundImage = gradientMatch[0]; 665 } 666 } else { 667 const colorMatch = styleDef.style.match(/background-color:\s*([^;]+);?/i); 668 if (colorMatch && colorMatch[1]) { 669 comment.style.backgroundColor = colorMatch[1]; 670 } 671 } 672 673 if (styleDef.textColor) { 674 comment.style.color = styleDef.textColor; 675 comment.style.caretColor = styleDef.textColor; 676 677 // Apply also to inner comment title and quote elements if any 678 const spanCommentTitle = comment.querySelector('span.comment-title'); 679 if(spanCommentTitle) { 680 spanCommentTitle.style.color = styleDef.textColor; 681 } 682 const spanCommentQuote = comment.querySelector('span.quote'); 683 if(spanCommentQuote) { 684 spanCommentQuote.style.color = styleDef.textColor; 685 } 686 const spanCommentBlockquote = comment.querySelector('blockquote > div'); 687 if(spanCommentBlockquote) { 688 spanCommentBlockquote.style.color = styleDef.textColor; 689 } 690 } 691 692 if (styleDef.textAlign) { 693 comment.style.textAlign = styleDef.textAlign; 694 } 695 696 // Default styles 697 comment.style.fontSize = '30px'; 698 comment.style.padding = '10%'; 699 comment.style.lineHeight = 'normal'; 700 comment.style.borderRadius = '6px'; 701 } 702 }); 703 } 704 705 if (this.ta) { 706 this.backgroundsPanel = document.createElement('div'); 707 this.backgroundsPanel.id = 'comments-form-backgroundspanel'; 708 this.backgroundsPanel.setAttribute('class', 'comment-form-close'); 709 this.backgroundsPanel.style.maxHeight = '300px'; 710 this.backgroundsPanel.style.overflowY = 'auto'; 711 712 if (this.bbcPanel) { 713 document.body.appendChild(this.backgroundsPanel); 714 var jc = this, 715 f = function(e) { 716 var bp = jc.backgroundsPanel, 717 p = jc.getElementPos(e); 718 if (bp) { 719 bp.className = (bp.className === '' || bp.className === 'comment-form-close') ? 'comment-form-open' : 'comment-form-close'; 720 var bps = bp.style; 721 bps.left = p.left + "px"; 722 bps.top = p.bottom + e.offsetHeight + "px"; 723 bps.zIndex = 99; 724 } 725 return false; 726 }; 727 this.bbcPanel.appendChild(this.createButton(null, 'Styles', 'bbcode-background', f)); 728 } else { 729 this.backgroundsPanel.className = 'backgrounds'; 730 this.ta.parentNode.insertBefore(this.backgroundsPanel, this.ta); 731 } 732 } 733 }, 734 addCounter: function(m, pre, post, className) { 735 if (this.ta) { 736 if (pre != null) { 737 this.l10n.counterPre = pre; 738 } 739 if (post != null) { 740 this.l10n.counterPost = post; 741 } 742 var ch = document.createElement('span'); 743 ch.className = className != null ? className : ''; 744 var t1 = document.createTextNode(this.l10n.counterPre + ' '), 745 t2 = document.createTextNode(' ' + this.l10n.counterPost); 746 var c = document.createElement('span'); 747 ch.appendChild(t1); 748 ch.appendChild(c); 749 ch.appendChild(t2); 750 if (this.resizable) {
751 if (this.grippie != null) { 752 this.grippie.appendChild(ch); 753 } 754 } else { 755 var d = document.createElement('div'); 756 d.className = 'counterpanel'; 757 this.ta.parentNode.insertBefore(d, this.ta.nextSibling); 758 d.appendChild(ch); 759 } 760 this.counter = { 761 e: c, 762 max: m 763 }; 764 this.updateCounter(); 765 } 766 }, 767 addGrippie: function() { 768 this.offset = null; 769 this.dragging = false; 770 this.grippie = document.createElement('div'); 771 this.grippie.className = 'grippie'; 772 this.ta.parentNode.insertBefore(this.grippie, this.ta.nextSibling); 773 var th = this; 774 this.events.add(this.grippie, 'mousedown', function(e) { 775 return th.onMouseDown(e); 776 }); 777 }, 778 updateCounter: function() { 779 if (this.counter != null) { 780 var ta = this.ta, 781 e = this.counter.e; 782 try { 783 var n = document.createElement(e.tagName), 784 v = this.counter.max; 785 if (ta.value.length > 0) { 786 v = v - ta.value.length; 787 var ln = ta.value.match(/[^\r]\n/g); 788 if (ln) { 789 v = v - ln.length; 790 } 791 } 792 n.innerHTML = (v >= 0) ? v : 0; 793 e.parentNode.replaceChild(n, e); 794 this.counter.e = n; 795 } catch (ex) {} 796 } 797 }, 798 mousePosition: function(e) { 799 var px = 0, 800 py = 0; 801 if (!e) { 802 e = window.event; 803 } 804 if (e.pageX || e.pageY) { 805 px = e.pageX; 806 py = e.pageY; 807 } else if (e.clientX || e.clientY) { 808 px = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; 809 py = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; 810 } 811 return { 812 x: px, 813 y: py 814 }; 815 }, 816 onChange: function() { 817 this.updateCounter(); 818 return false; 819 }, 820 onMouseDown: function(e) { 821 this.offset = this.mousePosition(e).y; 822 this.height = this.ta.clientHeight; 823 this.dragging = true; 824 var th = this; 825 this.events.add(document, 'mousemove', function(e) { 826 return th.onMouseMove(e); 827 }); 828 this.events.add(document, 'mouseup', function(e) { 829 return th.onMouseUp(e); 830 }); 831 return false; 832 }, 833 onMouseUp: function(e) { 834 this.dragging = false; 835 }, 836 onMouseMove: function(e) { 837 if (this.dragging) this.ta.style.height = Math.max(this.defaultHeight, this.height + this.mousePosition(e).y - this.offset) + 'px'; 838 return false; 839 } 840}; 841 842var JCommentScroll = JCommentScroll || { 843 getElementRect: function(e) { 844 var x = 0, 845 y = 0, 846 w = e.offsetWidth, 847 h = e.offsetHeight; 848 if (e.getBoundingClientRect) { 849 var b = e.getBoundingClientRect(), 850 de = document.documentElement, 851 db = document.body; 852 var st = window.pageYOffset || de.scrollTop || db.scrollTop; 853 var sl = window.pageXOffset || de.scrollLeft || db.scrollLeft; 854 var ct = de.clientTop || db.clientTop || 0; 855 var cl = de.clientLeft || db.clientLeft || 0; 856 x = b.left + sl - cl; 857 y = b.top + st - ct; 858 } else { 859 while (e.offsetParent !== null) { 860 x += e.offsetLeft; 861 y += e.offsetTop; 862 e = e.offsetParent; 863 } 864 x = Math.round(x); 865 y = Math.round(y); 866 } 867 return [x, y, x + w, y + h]; 868 }, 869 getPageRect: function() { 870 var de = document.documentElement, 871 db = document.body; 872 var x = window.pageXOffset || de.scrollLeft || db.scrollLeft; 873 var y = window.pageYOffset || de.scrollTop || db.scrollTop; 874 var w = 'innerWidth' in window ? window.innerWidth : (de.clientWidth || db.clientWidth);
875 var h = 'innerHeight' in window ? window.innerHeight : (de.clientHeight || db.clientHeight); 876 return [x, y, x + w, y + h]; 877 }, 878 scroll: function(element) { 879 var a = this.getElementRect(element), 880 b = this.getPageRect(); 881 if (!(a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1])) { 882 window.scrollTo(a[0], a[1]); 883 } 884 } 885}; 886 887JCommentForm.prototype = { 888 id: null, 889 form: null, 890 events: null, 891 editor: null, 892 elements: {}, 893 store: new Array('name', 'email', 'homepage'), 894 fadeTimer: null, 895 896 init: function(id, editor) { 897 this.id = id; 898 this.form = this.$(id); 899 this.editor = editor; 900 this.events = new JCommentEvents(); 901 this.setElements(new Array('name', 'email', 'homepage', 'title', 'comment', 'privacy')); 902 this.restoreValues(); 903 this.clear('captcha'); 904 this.setCaptcha(); 905 }, 906 setCaptcha: function() { 907 this.captchaImage = this.$(this.id + '-captcha-image'); 908 this.register('captcha'); 909 }, 910 setEditor: function(e) { 911 this.editor = e; 912 }, 913 setElements: function(e) { 914 for (var i = 0; i < e.length; i++) { 915 try { 916 this.register(e[i]); 917 } catch (e) {} 918 } 919 }, 920 $: function(e) { 921 return JComment.prototype.$(e); 922 }, 923 register: function(n) { 924 var f = this, 925 e = this.$(this.id + '-' + n); 926 if (e) { 927 this.elements[n] = e; 928 JCommentInput.prototype.register(e); 929 this.events.add(e, !window.opera && document.all ? 'keydown' : 'keypress', function(e) { 930 return f.keypress(e); 931 }); 932 } 933 }, 934 error: function(n) { 935 var e = this.elements[n]; 936 if (e) { 937 e.focus(); 938 var c = e.className.replace('/\berror\b/g', '') + ' error'; 939 e.className = c.replace(/\s{2,}/g, ' '); 940 } 941 }, 942 943 clear: function(n) { 944 if (n == null) { 945 if (this.form != null) { 946 this.form.reset(); 947 } 948 return; 949 } 950 switch (n) { 951 case 'comment': 952 if (this.editor != null) { 953 this.editor.clear(); 954 } 955 break; 956 case 'captcha': 957 var cim = this.captchaImage, 958 cin = this.elements['captcha']; 959 if (cim) { 960 var r = new String(Math.floor(Math.random() * 100000)); 961 if (/\d+$/g.test(cim.src)) { 962 cim.src = cim.src.replace(/\d+$/g, r); 963 } else if (/\?/g.test(cim.src)) { 964 cim.src = cim.src + '&r=' + r; 965 } else { 966 cim.src = cim.src + '?r=' + new String(Math.floor(Math.random() * 100000)); 967 } 968 } 969 if (cin) { 970 cin.value = ''; 971 } 972 break; 973 default: 974 var e = this.elements[n]; 975 if (e) { 976 e.value = ''; 977 } 978 break; 979 } 980 }, 981 focus: function(n) { 982 var e; 983 if (n == null) { 984 for (var nm in this.elements) { 985 e = this.elements[nm]; 986 if (e) { 987 e.focus(); 988 break; 989 } 990 } 991 } else { 992 e = this.elements[n]; 993 if (e) { 994 e.focus(); 995 } 996 } 997 }, 998 keypress: function(e) { 999 if (e.ctrlKey && (e.keyCode == 13 || (e.type == 'keypress' && e.keyCode == 10))) { 1000 this.submit(); 1001 e.returnValue = false; 1002 return this.events.cancel(e); 1003 } 1004 return this.keypressed(e); 1005 }, 1006 add: function(n, i, v) { 1007 if (this.form != null) { 1008 var e = document.createElement('input'); 1009 e.setAttribute('type', 'hidden'); 1010 e.setAttribute('name', n); 1011 e.setAttribute('id', i); 1012 e.setAttribute('value', v); 1013 this.form.appendChild(e); 1014 } 1015 }, 1016 remove: function(i) { 1017 var e = this.$(i); 1018 if (e) { 1019 e.value = 0; 1020 e.parentNode.removeChild(e); 1021 } 1022 }, 1023 setText: function(n, t) { 1024 if (n == 'comment') { 1025 if (this.editor != null) { 1026 this.editor.clear(); 1027 this.editor.insertText(t); 1028 } 1029 } else { 1030 var e = this.elements[n]; 1031 if (e) { 1032 e.value = t; 1033 } 1034 } 1035 }, 1036 insertText: function(n, t) { 1037 if (n == 'comment') { 1038 if (this.editor != null) { 1039 this.editor.insertText(t); 1040 } 1041 } else { 1042 var e = this.elements[n]; 1043 if (e) { 1044 e.value += t; 1045 } 1046 } 1047 },
1048 storeValues: function() { 1049 for (var i = 0; i < this.store.length; i++) { 1050 try { 1051 var el = JComment.prototype.$(this.id + '-' + this.store[i]); 1052 if (el) { 1053 JComment.prototype.setCookie(this.store[i], encodeURIComponent(el.value), 14); 1054 } 1055 } catch (e) {} 1056 } 1057 }, 1058 restoreValues: function() { 1059 for (var i = 0; i < this.store.length; i++) { 1060 try { 1061 var el = JComment.prototype.$(this.id + '-' + this.store[i]); 1062 if (el) { 1063 if (el.type && el.type == 'hidden') { 1064 return; 1065 } else { 1066 el.value = decodeURIComponent(JComment.prototype.getCookie(this.store[i])); 1067 } 1068 } 1069 } catch (e) {} 1070 } 1071 }, 1072 submit: function() {}, 1073 keypressed: function(e) {} 1074}; 1075 1076JCommentIndicator.prototype = { 1077 e: null, 1078 init: function() { 1079 if (this.e == null) { 1080 this.e = document.createElement('div'); 1081 this.e.className = 'busy'; 1082 } 1083 }, 1084 move: function(p, b) { 1085 if (p) { 1086 if (this.e.parentNode) { 1087 this.e.parentNode.removeChild(this.e); 1088 } 1089 if (b) { 1090 p.insertBefore(this.e, b); 1091 } else { 1092 p.appendChild(this.e); 1093 } 1094 } 1095 }, 1096 show: function() { 1097 this.e.style.display = 'block'; 1098 }, 1099 hide: function() { 1100 this.e.style.display = 'none'; 1101 }, 1102 start: function(p, b) { 1103 this.move(p, b); 1104 this.show(); 1105 }, 1106 stop: function() { 1107 this.hide(); 1108 } 1109}; 1110 1111JComment.prototype = { 1112 oi: null, 1113 og: null, 1114 requestURI: '', 1115 busy: null, 1116 form: null, 1117 cache: {}, 1118 mode: 'add', 1119 readyList: [], 1120 isReady: false, 1121 1122 init: function(oi, og, r) { 1123 this.oi = oi; 1124 this.og = og; 1125 this.busy = new JCommentIndicator(); 1126 this.requestURI = r; 1127 var th = this; 1128 jtajax.startLoading = function() { 1129 th.busy.show(); 1130 }; 1131 jtajax.finishLoading = function() { 1132 th.busy.hide(); 1133 }; 1134 }, 1135 reinit: function(oi, og) { 1136 this.oi = oi; 1137 this.og = og; 1138 var foi = this.$('object_id'); 1139 if (foi) { 1140 foi.value = oi; 1141 } 1142 var fog = this.$('object_group'); 1143 if (fog) { 1144 fog.value = og; 1145 } 1146 this.showPage(oi, og, 0); 1147 }, 1148 setForm: function(f) { 1149 this.form = f; 1150 this.form_id = f.id; 1151 this.setMode('add', null); 1152 var jc = this; 1153 this.form.submit = function() { 1154 jc.saveComment(); 1155 }; 1156 this.form.keypressed = function(e) { 1157 if (e.keyCode == 27 && jc.mode == 'reply') { 1158 jc.restoreForm(false); 1159 } 1160 }; 1161 f.form.classList.add('jcomment-form-initialized'); 1162 this.formLoaded(); 1163 }, 1164 setList: function(l) { 1165 this.list_id = l; 1166 }, 1167 setMode: function(m, i) { 1168 var b = this.$('comments-form-cancel'), 1169 jc = this; 1170 if (b != null) { 1171 b.style.display = (m != 'add') ? '' : 'none'; 1172 b.onclick = (m == 'edit' ? function() { 1173 jc.cancelEdit(i); 1174 } : (m == 'reply' ? function() { 1175 jc.cancelReply(); 1176 } : null)); 1177 } 1178 this.mode = m; 1179 }, 1180 $: function(id) { 1181 if (!id) { 1182 return null; 1183 } 1184 var e = document.getElementById(id); 1185 if (!e && document.all) { 1186 e = document.all[id]; 1187 } 1188 return e; 1189 }, 1190 ajax: function(f, a, fid) { 1191 var r, prevURI = ''; 1192 try { 1193 prevURI = jtajax.options.url; 1194 jtajax.setup({ 1195 url: this.requestURI 1196 }); 1197 r = jtajax.call(f, a, 'post', fid); 1198 jtajax.options.url = prevURI; 1199 } catch (e) { 1200 jtajax.options.url = prevURI; 1201 } 1202 return r; 1203 }, 1204 initOnReady: function() { 1205 if (this.isReadyInited) return; 1206 this.isReadyInited = 1; 1207 var jc = this; 1208 jc.ready(jc); 1209 }, 1210 onReady: function(f) { 1211 if (this.isReady) { 1212 f(); 1213 } else { 1214 var jc = this; 1215 jc.readyList.push(f); 1216 jc.initOnReady(); 1217 } 1218 }, 1219 ready: function() { 1220 var jc = window.jcomment; 1221 if (jc.isReady || jc.readyList == null) return; 1222 jc.isReady = 1; 1223 for (var i = 0, len = jc.readyList.length; i < len; i++) { 1224 try { 1225 jc.readyList[i](); 1226 } catch (e) {} 1227 } 1228 jc.readyList = null; 1229 }, 1230 setAntiCache: function(c, p, f) { 1231 jc.isReady = 1; 1232 this.isReady = 1; 1233 this.aca = c; 1234 this.acp = p; 1235 this.acf = f; 1236 this.onReady(this.loadComments); 1237 }, 1238 loadComments: function() { 1239 var jc = window.jcomment; 1240 var l = document.location.href, 1241 lc = true, 1242 i = l.lastIndexOf('#comment-'); 1243 jc.clear('captcha'); 1244 if (jc.aca) { 1245 if (i != 0) { 1246 var c = l.substring(i + 9, l.length); 1247 if (!isNaN(c)) { 1248 lc = false; 1249 jc.showComment(c); 1250 } 1251 } 1252 } 1253 if (jc.acp) { 1254 if (lc) { 1255 jc.showPage(jc.oi, jc.og, 0); 1256 } 1257 } 1258 if (jc.acf) { 1259 if (l.lastIndexOf('#addcomments') != -1) { 1260 jc.showForm(jc.oi, jc.og, 'comments-form-link'); 1261 } 1262 } 1263 },
1264 setCookie: function (n, v, d) { 1265 sessionStorage.setItem("jc_" + n, v); 1266 }, 1267 getCookie: function (n) { 1268 var value = sessionStorage.getItem("jc_" + n); 1269 return value !== null ? value : ''; 1270 }, 1271 removeCookie: function (n) { 1272 sessionStorage.removeItem("jc_" + n); 1273 }, 1274 scrollTo: function(n) { 1275 var e = this.$(n); 1276 if (e) { 1277 JCommentScroll.scroll(e); 1278 } 1279 }, 1280 scrollToList: function() { 1281 this.scrollTo(this.list_id); 1282 }, 1283 scrollToForm: function() { 1284 this.scrollTo(this.form_id); 1285 }, 1286 scrollToComment: function(id) { 1287 this.scrollTo('comment-' + id); 1288 }, 1289 moveElement: function(e, p, b) { 1290 if (e) { 1291 if (p) { 1292 if (e.parentNode) { 1293 e.parentNode.removeChild(e); 1294 } 1295 if (b) { 1296 p.insertBefore(e, b); 1297 } else { 1298 p.appendChild(e); 1299 } 1300 } 1301 } 1302 }, 1303 createElement: function(t, i, c) { 1304 var e = document.createElement(t); 1305 if (i) { 1306 e.setAttribute('id', i); 1307 } 1308 if (c) { 1309 e.className = c; 1310 } 1311 return e; 1312 }, 1313 fade: function(id, s, e, m) { 1314 var speed = Math.round(m / 100), 1315 timer = 0; 1316 if (s > e) { 1317 for (var i = s; i >= e; i--) { 1318 setTimeout("JComment.prototype.setOpacity('" + id + "'," + i + ")", (timer * speed)); 1319 timer++; 1320 } 1321 var o = JComment.prototype.$(id); 1322 if (o) { 1323 setTimeout(function() { 1324 o.style.display = 'none'; 1325 }, ((s - e) * speed)); 1326 } 1327 } else if (s < e) { 1328 for (var i = s; i <= e; i++) { 1329 setTimeout("JComment.prototype.setOpacity('" + id + "'," + i + ")", (timer * speed)); 1330 timer++; 1331 } 1332 } 1333 }, 1334 setOpacity: function(id, opacity) { 1335 var e = this.$(id); 1336 if (e) { 1337 var s = e.style; 1338 s.opacity = (opacity / 100); 1339 s.MozOpacity = (opacity / 100); 1340 s.KhtmlOpacity = (opacity / 100); 1341 s.filter = "alpha(opacity=" + opacity + ")"; 1342 } 1343 }, 1344 clear: function(n) { 1345 if (this.form != null) { 1346 this.form.clear(n); 1347 } 1348 }, 1349 insertText: function(t) { 1350 if (this.form != null) { 1351 this.form.insertText('comment', t); 1352 } else { 1353 var jc = this; 1354 window.setTimeout(function() { 1355 jc.insertText(t); 1356 }, 500); 1357 } 1358 }, 1359 busyList: function() { 1360 if (this.list_id) { 1361 var l = this.$(this.list_id); 1362 if (l) { 1363 this.busy.move(l.parentNode, l); 1364 } 1365 } 1366 }, 1367 busyForm: function() { 1368 if (this.form_id) { 1369 var f = this.$(this.form_id); 1370 if (f) { 1371 this.busy.move(f.parentNode, f); 1372 } 1373 } 1374 }, 1375 busyComment: function(i) { 1376 this.busy.move(this.$('comment-item-' + i), null); 1377 }, 1378 saveComment: function() { 1379 var f = ''; 1380 // Auto-close all advanced panels if any open 1381 ['comments-form-backgroundspanel', 'comments-form-emojispanel'].forEach(function(id) { 1382 var panel = document.getElementById(id); 1383 if (panel && panel.classList.contains('comment-form-open')) { 1384 if (panel.classList.replace) { 1385 panel.classList.replace('comment-form-open', 'comment-form-close'); 1386 } 1387 } 1388 }); 1389 1390 // JS Captcha validation 1391 var $field = jQuery('#jcomment_recaptcha_control'); 1392 if ($field.length && !window.jcommentrhvvalidation) { 1393 // Add error class 1394 jQuery('#jcomment_recaptcha_label').addClass('jcomment_label_validate_recaptcha'); 1395 1396 //Bind blur event 1397 $field.on('change', function() { 1398 jQuery('#jcomment_recaptcha_label').removeClass('jcomment_label_validate_recaptcha'); 1399 }); 1400 1401 jQuery('label.jcomment_label_validation_recaptcha').remove(); 1402 jQuery('#jcomment_recaptcha_container').after('<label class="jcomment_label_validation jcomment_label_validation_recaptcha">* ' + 1403 jQuery('#jcomment_recaptcha_control').data('validation-label') + 1404 '</label>'); 1405 return false; 1406 } 1407 1408 // Validate rating 1409 if(document.querySelector('#jcomment-star-rating')) { 1410 if(document.querySelector('#jcomment-star-rating div.stars') && document.querySelectorAll('#jcomment-star-rating div.stars a.star.fullStar').length == 0 && 1411 (jcommentRatingRequired == 1 || (jcommentRatingRequired == 2 && this.mode != 'reply'))) { 1412 if(!document.querySelector('label.jcomment_label_validation_rating')) { 1413 document.querySelector('#jcomment-star-rating div.stars').insertAdjacentHTML('afterend', '<label class="jcomment_label_validation jcomment_label_validation_rating">* ' + 1414 document.querySelector('#jcomment-star-rating').dataset.validationLabel + 1415 '</label>'); 1416 } 1417 return false; 1418 } 1419 } 1420 1421 if (this.mode != 'edit') { 1422 f = 'JCommentAddComment'; 1423 this.busyForm(); 1424 if (this.form) { 1425 this.form.storeValues();
1426 } 1427 this.busy.show(); 1428 } else { 1429 f = 'JCommentSaveComment'; 1430 this.busy.show(); 1431 } 1432 var emptyState = document.querySelector('div.jcomment-empty-state'); 1433 if(emptyState) { 1434 emptyState.remove(); 1435 document.querySelector('h4.jcomment-empty-state').remove(); 1436 } 1437 1438 return this.ajax(f, null, this.form_id); 1439 }, 1440 editComment: function(i) { 1441 this.busyComment(i); 1442 var a = arguments; 1443 if (this.form == null) { 1444 a = new Array(i, 1); 1445 } 1446 return this.ajax('JCommentEditComment', a); 1447 }, 1448 cancelEdit: function(i) { 1449 if ((!this.cache[i]) || (this.cache[i] == '')) { 1450 this.$('comment-body-' + i).innerHTML = this.cache[i]; 1451 this.cache[i] = ''; 1452 } 1453 if (this.form) { 1454 this.form.remove('comment-id-hidden-' + i); 1455 this.restoreForm(true); 1456 } 1457 var t = this.$('comment-toolbar-' + i); 1458 if (t) { 1459 t.style.display = ''; 1460 } 1461 1462 // Show the 'Add comments' line 1463 var addCommentLine = document.querySelector('div.jcomment-container-form h4'); 1464 if (addCommentLine) { 1465 addCommentLine.style.display = ''; 1466 } 1467 1468 // Reset rating 1469 if(typeof(jQuery.fn.rating) !== 'undefined') { 1470 // Check for reviews and reset/add full stars 1471 var stars = document.querySelectorAll('#comments-form div.stars a.star'); 1472 if(stars && stars.length) { 1473 for(var i = 1; i <= 5; i++) { 1474 var starToReset = document.querySelector('#comments-form div.stars a.star[data-title="' + i + '"]'); 1475 starToReset.classList.remove('fullStar'); 1476 } 1477 } 1478 } 1479 1480 return this.ajax('JCommentCancelComment', arguments); 1481 }, 1482 cancelReply: function() { 1483 if (this.form) { 1484 this.form.remove('comment-parent-id-hidden'); 1485 this.restoreForm(false); 1486 1487 // Show the 'Add comments' line 1488 var addCommentLine = document.querySelector('div.jcomment-container-form h4'); 1489 if (addCommentLine) { 1490 addCommentLine.style.display = ''; 1491 } 1492 1493 // Reset rating 1494 if(typeof(jQuery.fn.rating) !== 'undefined') { 1495 // Check for reviews and reset/add full stars 1496 var stars = document.querySelectorAll('#comments-form div.stars a.star'); 1497 if(stars && stars.length) { 1498 for(var i = 1; i <= 5; i++) { 1499 var starToReset = document.querySelector('#comments-form div.stars a.star[data-title="' + i + '"]'); 1500 starToReset.classList.remove('fullStar'); 1501 } 1502 } 1503 } 1504 } 1505 }, 1506 quoteComment: function(i) { 1507 var a = arguments; 1508 if (this.form == null) { 1509 var ff = document.querySelector('#comments-form'); 1510 if(ff && !ff.classList.contains('jcomment-form-initialized')) { 1511 return; 1512 } 1513 a = new Array(i, 1); 1514 } 1515 return this.ajax('JCommentQuoteComment', a); 1516 }, 1517 publishComment: function(i) { 1518 if (this.form) { 1519 this.restoreForm(); 1520 } 1521 this.busyComment(i); 1522 return this.ajax('JCommentPublishComment', arguments); 1523 }, 1524 deleteComment: function(i) { 1525 this.busyComment(i); 1526 return this.ajax('JCommentDeleteComment', arguments); 1527 }, 1528 jump2email: function(i) { 1529 return this.ajax('JCommentJump2email', arguments); 1530 }, 1531 updateList: function(t, m) { 1532 if (this.list_id) { 1533 var l = this.$(this.list_id); 1534 if (!l) { 1535 l = this.$('comments'); 1536 m = 'a'; 1537 } 1538 switch (m) { 1539 case 'a': 1540 l.innerHTML = l.innerHTML + t; 1541 break; 1542 case 'p': 1543 l.innerHTML = t + l.innerHTML; 1544 break; 1545 case 'r': 1546 l.parentNode.innerHTML = t; 1547 break; 1548 } 1549 } 1550 this.restoreForm(true); 1551 }, 1552 updateTree: function(t, r, m) { 1553 var l; 1554 if (r == null) { 1555 l = this.$('comments'); 1556 if (l) { 1557 l.innerHTML = t; 1558 } 1559 return; 1560 } 1561 l = this.$('comments-list-' + r); 1562 if (!l) { 1563 var p = this.$('comment-item-' + r); 1564 if (p) { 1565 this.busyComment(r); 1566 l = this.createElement('div', 'comments-list-' + r, 'comments-list'); 1567 l.innerHTML = t; 1568 p.parentNode.insertBefore(l, p.nextSibling); 1569 } 1570 } else { 1571 l.innerHTML = (m == 'b' ? t + l.innerHTML : l.innerHTML + t); 1572 } 1573 this.restoreForm(true); 1574 }, 1575 updateComment: function(id, t) { 1576 if (t == '') { 1577 var c = this.$('comment-item-' + id); 1578 c.parentNode.removeChild(c); 1579 var l = this.$('comments-list-' + id); 1580 if (l) { 1581 l.parentNode.removeChild(l); 1582 } 1583 return; 1584 } 1585 this.$('comment-item-' + id).innerHTML = t; 1586 var te = this.$('comment-toolbar-' + id); 1587 if (te) { 1588 te.style.display = ''; 1589 } 1590 if (this.form) { 1591 this.form.remove('comment-id-hidden-' + id); 1592 this.restoreForm(true); 1593 } 1594 }, 1595 voteComment: function(i) { 1596 var v = this.$('comment-vote-holder-' + i); 1597 if (v) { 1598 v.innerHTML = ''; 1599 this.busy.start(v, null); 1600 } 1601 return this.ajax('JCommentVoteComment', arguments); 1602 }, 1603 reactComment: function(i) { 1604 return this.ajax('JCommentReactComment', arguments); 1605 }, 1606 updateVote: function(i, t) { 1607 this.busy.stop(); 1608 var c = this.$('comment-vote-holder-' + i); 1609 if (c) { 1610 c.innerHTML = t; 1611 } 1612 }, 1613 showComment: function(id) { 1614 return this.ajax('JCommentShowComment', arguments); 1615 }, 1616 showPage: function(i, g, p, search) { 1617 if (this.form) { 1618 this.restoreForm(); 1619 } 1620 var l = this.$(this.list_id); 1621 if (!l) { 1622 l = this.$(this.list_id + '-0'); 1623 if (l) { 1624 this.list_id = this.list_id + '-0'; 1625 } 1626 } 1627 1628 // Manage show comments/form by button 1629 var addCommentsElementHidden = document.querySelectorAll('.showsearch-comments-load-bybutton'); 1630 if(addCommentsElementHidden && addCommentsElementHidden.length) { 1631 for(commentElementHidden of addCommentsElementHidden) { 1632 commentElementHidden.classList.remove('showsearch-comments-load-bybutton'); 1633 } 1634 } 1635 1636 this.busyList(); 1637 return this.ajax('JCommentShowPage', arguments); 1638 }, 1639 showForm: function(i, g, t, viewname) { 1640 if (this.form) { 1641 this.moveElement(this.form.form, this.$(t)); 1642 return; 1643 } 1644 this.busyForm(); 1645 return this.ajax('JCommentShowForm', arguments); 1646 }, 1647 showEdit: function(id, n, e, h, t, txt) { 1648 var jc = this; 1649 if (this.form == null) { 1650 window.setTimeout(function() { 1651 jc.showEdit(id, n, e, h, t, txt); 1652 }, 500); 1653 return; 1654 } 1655 if ((!this.cache[id]) || (this.cache[id] == '')) { 1656 this.cache[id] = this.$('comment-body-' + id).innerHTML; 1657 } 1658 this.busy.stop(); 1659 var f = this.form, 1660 ff = this.form.form, 1661 c = this.$('comment-item-' + id); 1662 if (ff != null && c != null) { 1663 var root = document.documentElement; 1664 var computedBehavior = window.getComputedStyle(root).scrollBehavior; 1665 root.style.scrollBehavior = 'auto'; 1666 1667 f.add('id', 'comment-id-hidden-' + id, id); 1668 f.setText('name', n); 1669 f.setText('email', e); 1670 f.setText('homepage', h); 1671 f.setText('title', t); 1672 f.setText('comment', txt); 1673 1674 if(typeof(jQuery.fn.rating) !== 'undefined') { 1675 // Check for reviews and reset/add full stars 1676 var stars = document.querySelectorAll('#comment-item-' + id + ' div.jcomment_review_rating span.star'); 1677 if(stars && stars.length) { 1678 for(var i = 1; i <= 5; i++) { 1679 var starToReset = document.querySelector('#comments-form div.stars a.star[data-title="' + i + '"]'); 1680 starToReset.classList.remove('fullStar'); 1681 } 1682 } 1683 var ratings = document.querySelectorAll('#comment-item-' + id + ' div.jcomment_review_rating span.star.fullStar'); 1684 if(ratings && ratings.length) { 1685 var numberOfRatings = ratings.length; 1686 for(var i = 1; i <= numberOfRatings; i++) { 1687 var starToLight = document.querySelector('#comments-form div.stars a.star[data-title="' + i + '"]'); 1688 starToLight.classList.add('fullStar'); 1689 } 1690 } 1691 } 1692 1693 var d = this.$('comments-inline-edit'); 1694 if (d) { 1695 d.parentNode.removeChild(d); 1696 } else { 1697 d = this.createElement('div', 'comments-inline-edit', 'comments-inline-edit'); 1698 } 1699 c.appendChild(d); 1700 this.moveElement(ff, d);
1701 this.setMode('edit', id); 1702 1703 // Ensure all other toolbars are visible as there could a direct edit between messages 1704 var allMessagesHiddenToolbar = document.querySelectorAll('#comments-list p.toolbar[style*=none]'); 1705 if(allMessagesHiddenToolbar && allMessagesHiddenToolbar.length) { 1706 var numberOfHiddenToolbars = allMessagesHiddenToolbar.length; 1707 for(var m = 0; m < numberOfHiddenToolbars; m++) { 1708 allMessagesHiddenToolbar[m].removeAttribute('style'); 1709 } 1710 } 1711 1712 1713 // Hide the current edited message toolbar 1714 var te = this.$('comment-toolbar-' + id); 1715 if (te) { 1716 te.style.display = 'none'; 1717 } 1718 1719 // Hide the 'Add comments' line 1720 var addCommentLine = document.querySelector('div.jcomment-container-form h4'); 1721 if (addCommentLine) { 1722 addCommentLine.style.display = 'none'; 1723 } 1724 1725 // Check if there are styles enabled and if the comment has a style to be reapplied to the textarea 1726 var backgroundStylesPanel = document.querySelector('#comments-form-backgroundspanel'); 1727 if(backgroundStylesPanel) { 1728 var editedCommentBody = c.querySelector('div.comment-body'); 1729 if(editedCommentBody.dataset.style) { 1730 var editedStyle = editedCommentBody.dataset.style; 1731 var buttonStyle = document.querySelector(`button.bg-style-btn[data-name="${editedStyle}"]`); 1732 if(buttonStyle) { 1733 setTimeout(function(){ 1734 buttonStyle.click(); 1735 }, 1) 1736 } 1737 } 1738 } 1739 1740 this.scrollTo('comments-inline-edit'); 1741 this.form.focus('comment'); 1742 root.style.scrollBehavior = computedBehavior; 1743 } 1744 }, 1745 showReply: function(id, q) { 1746 this.cancelReport(); 1747 var jc = this, 1748 c = this.$('comment-item-' + id), 1749 d = this.$('comments-inline-edit'); 1750 if (d) { 1751 d.parentNode.removeChild(d); 1752 } else { 1753 d = this.createElement('div', 'comments-inline-edit', 'comments-inline-edit'); 1754 } 1755 c.appendChild(d); 1756 1757 // Hide the 'Add comments' line 1758 var addCommentLine = document.querySelector('div.jcomment-container-form h4'); 1759 if (addCommentLine) { 1760 addCommentLine.style.display = 'none'; 1761 } 1762 1763 if (!this.form) { 1764 var ff = document.querySelector('#comments-form'); 1765 if(ff && !ff.classList.contains('jcomment-form-initialized')) { 1766 return; 1767 } 1768 this.busyComment(id); 1769 var t = 'comments-inline-edit', 1770 h = this.$('comments-form-link'); 1771 if (h) { 1772 t = 'comments-form-link'; 1773 } 1774 this.showForm(this.oi, this.og, t); 1775 var pid = id; 1776 this.formLoaded = function() { 1777 var f = jc.form; 1778 if (f != null) { 1779 f.add('parent', 'comment-parent-id-hidden', pid); 1780 } 1781 jc.setMode('reply', pid); 1782 jc.moveElement(jc.form.form, jc.$('comments-inline-edit')); 1783 jc.form.focus(); 1784 if (q) { 1785 jc.quoteComment(id); 1786 } 1787 }; 1788 } else { 1789 var f = this.form, 1790 ff = this.form.form, 1791 p = this.$('comment-parent-id-hidden'); 1792 if (ff != null && c != null) { 1793 if (!p) { 1794 f.add('parent', 'comment-parent-id-hidden', id); 1795 } else { 1796 p.value = id; 1797 } 1798 this.moveElement(ff, d); 1799 this.setMode('reply', id); 1800 this.form.focus(); 1801 if (q) { 1802 this.quoteComment(id); 1803 } 1804 } 1805 } 1806 }, 1807 formLoaded: function() {}, 1808 restoreForm: function(c) { 1809 var f = this.form; 1810 if (f != null) { 1811 var ff = this.form.form; 1812 this.busy.stop(); 1813 if (ff != null) { 1814 if (c) { 1815 f.clear(null); 1816 } 1817 f.restoreValues();
1818 var a = this.$('addcomments'), 1819 p = this.$('comment-parent-id-hidden'); 1820 if (p) { 1821 p.value = 0; 1822 } 1823 this.moveElement(ff, a.parentNode, a); 1824 var d = this.$('comments-inline-edit'); 1825 if (d) { 1826 d.parentNode.removeChild(d); 1827 } 1828 this.setMode('add', null); 1829 } 1830 1831 // Reset Captcha state 1832 var $field = jQuery('#jcomment_recaptcha_control'); 1833 if ($field.length) { 1834 window.jcommentrhvvalidation = false; 1835 jQuery('#jcomment_recaptcha_control').removeAttr('style'); 1836 jQuery('#jcomment_recaptcha_success').remove(); 1837 jQuery('#jcomment_recaptcha_label').removeClass('jcomment_label_validate_recaptcha'); 1838 jQuery('label.jcomment_label_validation.jcomment_label_validation_recaptcha').remove(); 1839 } 1840 1841 // Reset textarea background style if any 1842 const ta = document.getElementById('comments-form-comment'); 1843 if (ta && ta.classList.contains('bg-colored')) { 1844 // Reset all styles applied to the textarea 1845 ta.removeAttribute('style'); 1846 ta.removeAttribute('data-active-style'); 1847 ta.classList.remove('bg-colored'); 1848 1849 // Reset placeholder and caret color 1850 ta.style.setProperty('--placeholder-color', ''); 1851 ta.style.caretColor = ''; 1852 1853 // Remove prepended line breaks if present 1854 ta.value = ta.value.replace(/^\n{3}/, ''); 1855 1856 // Clear hidden input field value 1857 const hiddenInput = document.getElementById('comment-style-name'); 1858 if (hiddenInput) { 1859 hiddenInput.value = ''; 1860 } 1861 1862 // Trigger input event to update placeholder behavior 1863 ta.dispatchEvent(new Event('input')); 1864 } 1865 } 1866 }, 1867 reportComment: function(id) { 1868 this.busyComment(id); 1869 this.cancelReply(); 1870 var c = this.$('comment-item-' + id), 1871 d = this.$('comments-inline-report'); 1872 if (d) { 1873 d.parentNode.removeChild(d); 1874 } else { 1875 d = this.createElement('div', 'comments-inline-report', 'comments-inline-report'); 1876 } 1877 c.appendChild(d); 1878 var a = new Array(id, 'comments-inline-report'); 1879 return this.ajax('JCommentShowReportForm', a); 1880 }, 1881 saveReport: function() { 1882 this.ajax('JCommentReportComment', null, 'comments-report-form'); 1883 return true; 1884 }, 1885 cancelReport: function() { 1886 var d = this.$('comments-inline-report'); 1887 if (d) { 1888 d.innerHTML = ''; 1889 d.parentNode.removeChild(d); 1890 } 1891 }, 1892 closeReport: function(m) { 1893 this.cancelReport(); 1894 if (m) { 1895 this.showMessage(m, 'info', 'comments-inline-report'); 1896 } 1897 }, 1898 banIP: function(id) { 1899 this.ajax('JCommentBanIP', arguments) 1900 }, 1901 error: function(m, t, n) { 1902 if (!t || t == '') { 1903 t = this.form_id; 1904 } 1905 this.showMessage(m, 'error', t); 1906 if (this.form != null) { 1907 this.form.error(n); 1908 } 1909 }, 1910 message: function(m, t) { 1911 if (!t || t == '') { 1912 t = this.form_id; 1913 } 1914 this.showMessage(m, 'info', t); 1915 }, 1916 showMessage: function(m, c, t) { 1917 clearTimeout(this.fadeTimer); 1918 var fe = this.$('comments-form-message'); 1919 var af = this.$(t); 1920 if (fe) { 1921 fe.parentNode.removeChild(fe); 1922 } 1923 fe = JComment.prototype.createElement('div', 'comments-form-message', ''); 1924 if (af) { 1925 JComment.prototype.moveElement(fe, af, af.firstChild); 1926 } else { 1927 alert(m); 1928 return; 1929 } 1930 if (!c) { 1931 c = 'info'; 1932 } 1933 fe.className = 'comments-form-message-' + c; 1934 fe.innerHTML = m; 1935 fe.style.display = 'block'; 1936 JComment.prototype.setOpacity(fe.id, 100); 1937 this.fadeTimer = setTimeout(function() { 1938 JComment.prototype.fade('comments-form-message', 100, 0, 1000); 1939 }, 6000);
1940 JCommentScroll.scroll(fe); 1941 }, 1942 1943 subscribe: function(o, g) { 1944 return this.ajax('JCommentSubscribe', arguments); 1945 }, 1946 unsubscribe: function(o, g) { 1947 return this.ajax('JCommentUnsubscribe', arguments); 1948 }, 1949 updateSubscription: function(m, t) { 1950 var e = this.$('comments-subscription'); 1951 if (e) { 1952 var jc = this; 1953 e.innerHTML = t; 1954 e.onclick = m ? function() { 1955 jc.unsubscribe(jc.oi, jc.og); 1956 return false; 1957 } : function() { 1958 jc.subscribe(jc.oi, jc.og); 1959 return false; 1960 }; 1961 e.blur(); 1962 } 1963 }, 1964 go: function(l) { 1965 window.open(l); 1966 return false; 1967 } 1968}; 1969 1970JComment.reloadGravatar = function(image) { 1971 var urlWithoutQueryString = image.src.split("?")[0]; 1972 image.src = urlWithoutQueryString; 1973} 1974 1975JComment.initGRecaptcha = function(){ 1976 var $ = jQuery; 1977 if ($('#jcomment_recaptcha_control').length) { 1978 $('#jcomment_recaptcha_control').on('click change pointerdown', function(jqEvent) { 1979 // Detect human 1980 var eventX = jqEvent.clientX; 1981 var eventY = jqEvent.clientY; 1982 var pageX = jqEvent.pageX; 1983 var pageY = jqEvent.pageY; 1984 var isTrusted = false; 1985 if (typeof(jqEvent.originalEvent) !== 'undefined') { 1986 isTrusted = jqEvent.originalEvent.isTrusted; 1987 } 1988 if (eventX && eventY && pageX && pageY && isTrusted && !$(this).is(':checked')) { 1989 var animationObject = { 1990 width: 0, 1991 'margin-left': '18px' 1992 }; 1993 // Get if it's FF 1994 if (window.mozInnerScreenX || navigator.userAgent.indexOf('Firefox') > -1) { 1995 animationObject = { 1996 'opacity': 0 1997 } 1998 } 1999 2000 $(this).animate(animationObject, 500, function() { 2001 // Animation complete. 2002 $(this).after('<span id="jcomment_recaptcha_success"></span>'); 2003 $(this).hide(); 2004 window.jcommentrhvvalidation = true; 2005 $('#jcomment_recaptcha_label').removeClass('jcomment_label_validate_recaptcha'); 2006 setTimeout(function(element) { 2007 $('#jcomment_recaptcha_success').addClass('jcomment_animate'); 2008 }, 1); 2009 $('label.jcomment_label_validation_recaptcha').remove(); 2010 }); 2011 2012 return true; 2013 } 2014 2015 return false; 2016 }); 2017 } 2018} 2019 2020//Manage the optional ReCaptcha control 2021jQuery(function($) { 2022 JComment.initGRecaptcha(); 2023 2024 $(document).on('click', 'a.toolbar-button-ip', function(jqEvent) { 2025 // Toggle the tooltip 2026 var existingTooltip = $(this).next('div.jcomment_ip_popover'); 2027 if (existingTooltip.length) { 2028 existingTooltip.remove(); 2029 return true; 2030 } 2031 2032 var ipToLookup = $(this).data('ipaddress'); 2033 var webServiceEndpoint = 'https://json.geoiplookup.io/' + ipToLookup; 2034 $.get(webServiceEndpoint, function(response) { 2035 var emptyResponse = true; 2036 var marginOffset = 0; 2037 if (response) { 2038 var htmlIpInfo = '<ul class="jcomment_ipgeolocation">'; 2039 if (response.city) { 2040 htmlIpInfo += '<li>' + response.city + '</li>'; 2041 emptyResponse = false; 2042 marginOffset += 4; 2043 } 2044 2045 if (response.country_name) { 2046 htmlIpInfo += '<li>' + response.country_name + '</li>'; 2047 emptyResponse = false; 2048 marginOffset += 4; 2049 } 2050 2051 if (response.region) { 2052 htmlIpInfo += '<li>' + response.region + '</li>'; 2053 emptyResponse = false; 2054 marginOffset += 4; 2055 } 2056 } else { 2057 // Empty response 2058 htmlIpInfo = '-'; 2059 } 2060 // Empty response 2061 if (emptyResponse) { 2062 htmlIpInfo = '-'; 2063 } else { 2064 htmlIpInfo += '</ul>'; 2065 } 2066 2067 $(jqEvent.target).after('<div class="jcomment_ip_popover">' + htmlIpInfo + '<div class="jcomment-arrow-popover"></div></div>'); 2068 }, 'jsonp'); 2069 });
2070 // Ensure closing popovers when click on other DOM elements 2071 $(document).on('click', 'body', function(jqEvent){ 2072 if(!$(jqEvent.target).hasClass('toolbar-button-ip') && !$(jqEvent.target).parents('.jcomment_ip_popover').length) { 2073 $('div.jcomment_ip_popover').remove(); 2074 } 2075 }); 2076 2077 // Manage collapsing 2078 $(document).on('click', 'div.comments-list-collapsed div.comments-list-toggler, div.comments-list-expanded div.comments-list-toggler', function(jqEvent){ 2079 if($(jqEvent.target).parent('.comments-list').hasClass('comments-list-collapsed')) { 2080 var oppositeTitle = $(jqEvent.target).data('title-expanded'); 2081 $(jqEvent.target).text(oppositeTitle); 2082 $(jqEvent.target).removeClass('comments-list-collapsed').addClass('comments-list-expanded'); 2083 $(jqEvent.target).parent('.comments-list').removeClass('comments-list-collapsed').addClass('comments-list-expanded'); 2084 } else if($(jqEvent.target).parent('.comments-list').hasClass('comments-list-expanded')) { 2085 var oppositeTitle = $(jqEvent.target).data('title-collapsed'); 2086 $(jqEvent.target).text(oppositeTitle); 2087 $(jqEvent.target).removeClass('comments-list-expanded').addClass('comments-list-collapsed'); 2088 $(jqEvent.target).parent('.comments-list').removeClass('comments-list-expanded').addClass('comments-list-collapsed'); 2089 } 2090 2091 return false; 2092 }); 2093 2094 // Review instantiation 2095 if(typeof(jQuery.fn.rating) !== 'undefined') { 2096 $('#jcomment-star-rating').rating(function(vote, event) { 2097 $('input[name="comment_reviews_rating"]').val(vote); 2098 $('label.jcomment_label_validation.jcomment_label_validation_rating').remove(); 2099 }); 2100 } 2101});
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.