PageSourceSearch

https://calcstroy.ru/media/com_jcomments/js/jcomments-v4.0.js

js calcstroy.ru collected 2026-10-04 23:54:47 UTC 38,052 bytes, 1,541 lines download raw bytes

1function JCommentsEvents() {
2}
3
4function JCommentsInput() {
5}
6
7function JCommentsIndicator() {
8	this.init();
9}
10
11function JCommentsForm(id, editor) {
12	this.init(id, editor);
13}
14
15function JCommentsEditor(textarea, resizable) {
16	this.init(textarea, resizable);
17}
18
19function JComments(oi, og, r) {
20	this.init(oi, og, r);
21}
22
23JCommentsEvents.prototype = {
24	add: function (o, e, f) {
25		if (o.addEventListener) {
26			o.addEventListener(e, f, false);
27			return true;
28		} else if (o.attachEvent) {
29			return o.attachEvent("on" + e, f);
30		} else {
31			return false;
32		}
33	},
34	remove: function (o, e, f) {
35		if (o.removeEventListener) {
36			o.removeEventListener(e, f, false);
37		} else if (o.detachEvent) {
38			o.detachEvent("on" + e, o[e + f]);
39			o[e + f] = null;
40			o["e" + e + f] = null;
41		}
42	},
43	cancel: function (e) {
44		if (e.stopPropagation) {
45			e.cancelBubble = true;
46			e.preventDefault();
47			e.stopPropagation();
48		}
49		e.returnValue = false;
50		return false;
51	},
52	target: function (e) {
53		var t;
54		if (!e) e = window.event;
55		if (e.target) t = e.target; else if (e.srcElement) t = e.srcElement;
56		if (t.nodeType == 3) t = t.parentNode;
57		return t;
58	}
59};
60
61JCommentsInput.prototype = {
62	register: function (el) {
63		if (el) {
64			var th = this, events = new JCommentsEvents();
65			events.add(el, 'focus', function (e) {
66				return th.onFocus(e);
67			});
68			events.add(el, 'blur', function (e) {
69				return th.onBlur(e);
70			});
71		}
72	},
73	unregister: function (el) {
74		if (el) {
75			var th = this, events = new JCommentsEvents();
76			events.remove(el, 'focus', function (e) {
77				return th.onFocus(e);
78			});
79			events.remove(el, 'blur', function (e) {
80				return th.onBlur(e);
81			});
82		}
83	},
84	onFocus: function (e) {
85		var t = JCommentsEvents.prototype.target(e);
86		if (t != null) {
87			t.className = t.className.replace('error', '') + ' selected';
88		}
89	},
90	onBlur: function (e) {
91		var t = JCommentsEvents.prototype.target(e);
92		if (t != null) {
93			var c = t.className.replace('error', '');
94			c = c.replace('error', '');
95			c = c.replace('selected', '');
96			t.className = c.replace(/^\s+/g, "");
97		}
98	}
99};
100
101JCommentsEditor.prototype = {
102	ta: null,
103	l10n: {},
104	tags: {},
105	smiles: {},
106	events: null,
107	counter: null,
108	focused: false,
109	resizable: true,
110
111	init: function (textareaID, r) {
112		this.ta = JComments.prototype.$(textareaID);
113		this.l10n = { counterPre: '', counterPost: ' symbols left' };
114		this.resizable = r;
115		this.events = new JCommentsEvents();
116		this.defaultHeight = this.ta.clientHeight;
117		this.defaultRows = this.ta.rows;
118		if (this.resizable) {
119			this.addGrippie();
120		}
121		this.isWebkit = /webkit/.test(navigator.userAgent.toLowerCase());
122
123		var th = this;
124		this.events.add(document, !window.opera && document.all ? 'keydown' : 'keypress', function (e) {
125			return th.onKeyPress(e);
126		});
127		this.events.add(this.ta, 'click', function (e) {
128			th.closeSmiles();
129			return th.storeCaret(this.ta);
130		});
131		this.events.add(this.ta, 'select', function (e) {
132			return th.storeCaret(this.ta);
133		});
134		this.events.add(this.ta, 'change', function (e) {
135			th.onChange();
136			return th.storeCaret(this.ta);
137		});
138		this.events.add(this.ta, 'keyup', function (e) {
139			return th.onChange();
140		});
141		this.events.add(this.ta, 'focus', function (e) {
142			th.closeSmiles();
143			return th.focused = true;
144		});
145		this.events.add(this.ta, 'blur', function (e) {
146			return th.focused = false;
147		});
148	},
149	onKeyPress: function (e) {
150		if (!this.focused) {
151			return;
152		}
153		var k = String.fromCharCode(e.keyCode ? e.keyCode : e.charCode), t;
154		for (var id in this.tags) {
155			t = this.tags[id];
156			if (!t.key || k.toUpperCase() != t.key.toUpperCase()) continue;
157			if (t.ctrl && !e[t.ctrl + "Key"]) continue;
158			this.insertTag(id);
159			return this.events.cancel(e);
160		}
161		return e.returnValue;
162	},
163	defined: function (v) {
164		return (typeof (v) != "undefined");
165	},
166	clear: function () {
167		this.ta.value = '';
168		if (this.defaultHeight) {
169			this.ta.style.height = this.defaultHeight + 'px';
170		}
171		this.updateCounter();
172	},
173	focus: function () {
174		this.ta.focus();
175	},
176	storeCaret: function () {
177		var ta = this.ta;
178		if (ta.createTextRange) ta.caretPos = document.selection.createRange().duplicate();
179	},
180	getElementPos: function (e) {
181		var p = { left: 0, top: 0, right: 0, bottom: 0 };
182		while (e != null) {
183			p.left += e.offsetLeft;
184			p.top += e.offsetTop;
185			e = e.offsetParent;
186		}
187		p.right += p.left;
188		p.bottom += p.top;
189		return p;
190	},
191	getSelection: function () {
192		var ta = this.ta, s = '';
193		if (document.selection && document.selection.createRange) {
194			s = document.selection.createRange().text;
195		} else {
196			s = ta.value.substr(ta.selectionStart, ta.selectionEnd - ta.selectionStart);
197		}
198		return s;
199	},
200	insertText: function (text) {
201		var ta = this.ta;
202		if (this.defined(ta.caretPos) && ta.createTextRange) {
203			ta.focus();
204			var sel = document.selection.createRange();
205			sel.text = sel.text + text;
206			ta.focus();
207		} else if (this.defined(ta.selectionStart)) {
208			var ss = ta.value.substr(0, ta.selectionStart);
209			var se = ta.value.substr(ta.selectionEnd), sp = ta.scrollTop;
210			ta.value = ss + text + se;
211			if (ta.setSelectionRange) {
212				ta.focus();
213				ta.setSelectionRange(ss.length + text.length, ss.length + text.length);
214			}
215			ta.scrollTop = sp;
216		} else {
217			ta.value += text;
218			ta.focus(ta.value.length - 1);
219		}
220	},
221	surroundText: function (t1, t2) {
222		var ta = this.ta;
223		if (this.defined(ta.caretPos) && ta.createTextRange) {
224			var cp = ta.caretPos, tl = cp.text.length;
225			cp.text = cp.text.charAt(cp.text.length - 1) == ' ' ? t1 + cp.text + t2 + ' ' : t1 + cp.text + t2;
226			if (tl == 0) {
227				cp.moveStart("character", -t2.length);
228				cp.moveEnd("character", -t2.length);
229				cp.select();
230			} else {
231				ta.focus(cp);
232			}
233		} else if (this.defined(ta.selectionStart)) {
234			var ss = ta.value.substr(0, ta.selectionStart), se = ta.value.substr(ta.selectionEnd);
235			var sl = ta.value.substr(ta.selectionStart, ta.selectionEnd - ta.selectionStart);
236			var nc = ta.selectionStart, sp = ta.scrollTop;
237			ta.value = ss + t1 + sl + t2 + se;
238			if (ta.setSelectionRange) {
239				if (sl.length == 0) {
240					ta.setSelectionRange(nc + t1.length, nc + t1.length);
241				} else {
242					ta.setSelectionRange(nc, nc + t1.length + sl.length + t2.length);
243				}
244				ta.focus();
245			}
246			ta.scrollTop = sp;
247		} else {
248			ta.value += t1 + t2;
249			ta.focus(ta.value.length - 1);
250		}
251	},
252	insertTag: function (id) {
253		var tag = this.tags[id];
254		if (!tag) return;
255		var s = this.getSelection();
256		if (s.length > 0) {
257			this.surroundText(tag.open, tag.close);
258		}
259	},
260	initTags: function () {
261		if (this.bbc == null || this.bbc.length == 0) {
262			this.bbc = {};
263			this.bbc['b'] = { id: 'bbcode-b', open: '[b]', close: '[/b]', key: 'B', ctrl: 'ctrl', hint: 'Bold' };
264			this.bbc['i'] = { id: 'bbcode-i', open: '[i]', close: '[/i]', key: 'I', ctrl: 'ctrl', hint: 'Italic' };
265			this.bbc['u'] = { id: 'bbcode-u', open: '[u]', close: '[/u]', key: 'U', ctrl: 'ctrl', hint: 'Underline' };
266			this.bbc['s'] = { id: 'bbcode-s', open: '[s]', close: '[/s]', key: null, ctrl: null, hint: 'Strikeout' };
267			this.bbc['img'] = { id: 'bbcode-img', open: '[img]', close: '[/img]', key: null, ctrl: null, hint: 'Image' };
268			this.bbc['url'] = { id: 'bbcode-url', open: '[url]', close: '[/url]', key: null, ctrl: null, hint: 'Link' };
269			this.bbc['hide'] = {
270				id: 'bbcode-hide',
271				open: '[hide]',
272				close: '[/hide]',
273				key: null,
274				ctrl: null,
275				hint: 'Hidden'
276			};
277			this.bbc['quote'] = {
278				id: 'bbcode-quote',
279				open: '[quote]',
280				close: '[/quote]',
281				key: null,
282				ctrl: null,
283				hint: 'Quote'
284			};
285			this.bbc['list'] = {
286				id: 'bbcode-list',
287				open: '[list][*]',
288				close: '[/list]',
289				key: null,
290				ctrl: null,
291				hint: 'List'
292			};
293		}
294	},
295
296	createButton: function (i, t, c, f, img) {
297		var e;
298		if (img == null || img == "") {
299			e = document.createElement('a');
300			e.style.display = 'block';
301			e.setAttribute('href', '#');
302		} else {
303			e = document.createElement('img');
304			if (t) {
305				e.setAttribute('alt', t);
306			}
307			e.setAttribute('src', img);
308			if (!c) {
309				c = 'custombbcode';
310			}
311		}
312		if (i) {
313			e.setAttribute('id', i);
314		}
315		if (t) {
316			e.setAttribute('title', t);
317		}
318		if (c) {
319			e.className = c;
320		}
321		var ee = e;
322		e.onclick = (f != null ? function () {
323			f(ee);
324			return false;
325		} : function () {
326			return false;
327		});
328		return e;
329	},
330
331	addButton: function (id, h, p, ot, ct, css, img) {
332		if (this.ta) {
333			this.initTags();
334			var tag = this.bbc[id], th = this;
335			if (!tag) {
336				if (ot && ct) {
337					this.bbc[id] = { id: id, open: ot, close: ct, key: null, ctrl: null, hint: h };
338					tag = this.bbc[id];
339				} else {
340					return;
341				}
342			}
343			if (this.bbcPanel == null) {
344				this.bbcPanel = document.createElement('div');
345				this.bbcPanel.className = 'bbcode';
346				this.bbcPanel.style.display = 'block';
347				this.ta.parentNode.insertBefore(this.bbcPanel, this.ta);
348			}
349			var f = function () {
350				var s = th.getSelection();
351				if (s.length > 0) {
352					th.surroundText(tag.open, tag.close);
353				} else {
354					var v = prompt(p, '');
355					if (null != v && '' != v) {
356						th.insertText(tag.open + v + tag.close);
357					}
358				}
359				return false;
360			};
361			tag.e = this.createButton(tag.id, (h != null ? h : tag.hint), (css ? css : tag.id), f, img);
362			this.bbcPanel.appendChild(tag.e);
363			this.tags[tag.id] = tag;
364		}
365	},
366
367	initSmiles: function (path) {
368		this.smilesPath = path;
369
370		if (this.ta) {
371			this.smilesPanel = document.createElement('div');
372
373			if (this.bbcPanel) {
374				document.body.appendChild(this.smilesPanel);
375				this.smilesPanel.id = 'comments-form-smilespanel';
376				this.smilesPanel.setAttribute('style', 'display:none;top:0;left:0;position:absolute;');
377				this.smilesPanel.onclick = function () {
378					this.style.display = 'none';
379				};
380				var jc = this, f = function (e) {
381					var sp = jc.smilesPanel, p = jc.getElementPos(e);
382
383					if (sp) {
384						var sps = sp.style;
385						sps.display = (sps.display === 'none' || sps.display === '' ? 'block' : 'none');
386						sps.left = p.left + "px";
387						sps.top = p.bottom + e.offsetHeight + "px";
388						sps.zIndex = 99;
389					}
390
391					return false;
392				};
393
394				this.bbcPanel.appendChild(this.createButton(null, null, 'bbcode-smile', f));
395			} else {
396				this.smilesPanel.className = 'smiles';
397				this.ta.parentNode.insertBefore(this.smilesPanel, this.ta);
398			}
399		}
400	},
401	closeSmiles: function () {
402		if (this.smilesPanel && this.bbcPanel) {
403			this.smilesPanel.style.display = 'none';
404		}
405	},
406	addSmile: function (code, image) {
407		if (this.ta) {
408			if (!this.smilesPath || !this.smilesPanel) {
409				return;
410			}
411			var th = this, e = document.createElement('img');
412			e.setAttribute('src', this.smilesPath + image);
413			e.setAttribute('alt', code);
414			e.className = 'smile';
415			e.onclick = function () {
416				th.insertText(' ' + code + ' ');
417			};
418			this.smilesPanel.appendChild(e);
419		}
420	},
421	addCounter: function (m, pre, post, className) {
422		if (this.ta) {
423			if (pre != null) {
424				this.l10n.counterPre = pre;
425			}
426			if (post != null) {
427				this.l10n.counterPost = post;
428			}
429			var ch = document.createElement('span');
430			ch.className = className != null ? className : '';
431			var t1 = document.createTextNode(this.l10n.counterPre + ' '),
432				t2 = document.createTextNode(' ' + this.l10n.counterPost);
433			var c = document.createElement('span');
434			ch.appendChild(t1);
435			ch.appendChild(c);
436			ch.appendChild(t2);
437			if (this.resizable) {
438				if (this.grippie != null) {
439					this.grippie.appendChild(ch);
440				}
441			} else {
442				var d = document.createElement('div');
443				d.className = 'counterpanel';
444				this.ta.parentNode.insertBefore(d, this.ta.nextSibling);
445				d.appendChild(ch);
446			}
447			this.counter = { e: c, max: m };
448			this.updateCounter();
449		}
450	},
451	addGrippie: function () {
452		this.offset = null;
453		this.dragging = false;
454		this.grippie = document.createElement('div');
455		this.grippie.className = 'grippie';
456		this.ta.parentNode.insertBefore(this.grippie, this.ta.nextSibling);
457		var th = this;
458		this.events.add(this.grippie, 'mousedown', function (e) {
459			return th.onMouseDown(e);
460		});
461	},
462	updateCounter: function () {
463		if (this.counter != null) {
464			var ta = this.ta, e = this.counter.e;
465			try {
466				var n = document.createElement(e.tagName), v = this.counter.max;
467				if (ta.value.length > 0) {
468					v = v - ta.value.length;
469					var ln = ta.value.match(/[^\r]\n/g);
470					if (ln) {
471						v = v - ln.length;
472					}
473				}
474				n.innerHTML = (v >= 0) ? v : 0;
475				e.parentNode.replaceChild(n, e);
476				this.counter.e = n;
477			} catch (ex) {
478			}
479		}
480	},
481	mousePosition: function (e) {
482		var px = 0, py = 0;
483		if (!e) {
484			e = window.event;
485		}
486		if (e.pageX || e.pageY) {
487			px = e.pageX;
488			py = e.pageY;
489		} else if (e.clientX || e.clientY) {
490			px = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
491			py = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
492		}
493		return { x: px, y: py };
494	},
495	onChange: function () {
496		this.updateCounter();
497		if (this.ta && !this.isWebkit) {
498			var l = this.ta.value.split('\n');
499			this.ta.rows = (l.length < this.defaultRows) ? this.defaultRows : l.length + 1;
500		}
501		return false;
502	},
503	onMouseDown: function (e) {
504		this.offset = this.mousePosition(e).y;
505		this.height = this.ta.clientHeight;
506		this.dragging = true;
507		var th = this;
508		this.events.add(document, 'mousemove', function (e) {
509			return th.onMouseMove(e);
510		});
511		this.events.add(document, 'mouseup', function (e) {
512			return th.onMouseUp(e);
513		});
514		return false;
515	},
516	onMouseUp: function (e) {
517		this.dragging = false;
518	},
519	onMouseMove: function (e) {
520		if (this.dragging) this.ta.style.height = Math.max(this.defaultHeight, this.height + this.mousePosition(e).y - this.offset) + 'px';
521		return false;
522	}
523};
524
525var JCommentsScroll = JCommentsScroll || {
526	getElementRect: function (e) {
527		var x = 0, y = 0, w = e.offsetWidth, h = e.offsetHeight;
528		if (e.getBoundingClientRect) {
529			var b = e.getBoundingClientRect(), de = document.documentElement, db = document.body;
530			var st = window.pageYOffset || de.scrollTop || db.scrollTop;
531			var sl = window.pageXOffset || de.scrollLeft || db.scrollLeft;
532			var ct = de.clientTop || db.clientTop || 0;
533			var cl = de.clientLeft || db.clientLeft || 0;
534			x = b.left + sl - cl;
535			y = b.top + st - ct;
536		} else {
537			while (e.offsetParent !== null) {
538				x += e.offsetLeft;
539				y += e.offsetTop;
540				e = e.offsetParent;
541			}
542			x = Math.round(x);
543			y = Math.round(y);
544		}
545		return [x, y, x + w, y + h];
546	},
547	getPageRect: function () {
548		var de = document.documentElement, db = document.body;
549		var x = window.pageXOffset || de.scrollLeft || db.scrollLeft;
550		var y = window.pageYOffset || de.scrollTop || db.scrollTop;
551		var w = 'innerWidth' in window ? window.innerWidth : (de.clientWidth || db.clientWidth);
552		var h = 'innerHeight' in window ? window.innerHeight : (de.clientHeight || db.clientHeight);
553		return [x, y, x + w, y + h];
554	},
555	scroll: function (element) {
556		var a = this.getElementRect(element), b = this.getPageRect();
557		if (!(a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1])) {
558			window.scrollTo(a[0], a[1]);
559		}
560	}
561};
562
563JCommentsForm.prototype = {
564	id: null,
565	form: null,
566	events: null,
567	editor: null,
568	elements: {},
569	store: new Array('name', 'email', 'homepage'),
570	fadeTimer: null,
571
572	init: function (id, editor) {
573		this.id = id;
574		this.form = this.$(id);
575		this.editor = editor;
576		this.events = new JCommentsEvents();
577		this.setElements(new Array('name', 'email', 'homepage', 'title', 'comment'));
578		this.restoreValues();
579		this.clear('captcha');
580		this.setCaptcha();
581	},
582	setCaptcha: function () {
583		this.captchaImage = this.$(this.id + '-captcha-image');
584		this.register('captcha');
585	},
586	setEditor: function (e) {
587		this.editor = e;
588	},
589	setElements: function (e) {
590		for (var i = 0; i < e.length; i++) {
591			try {
592				this.register(e[i]);
593			} catch (e) {
594			}
595		}
596	},
597	$: function (e) {
598		return JComments.prototype.$(e);
599	},
600	register: function (n) {
601		var f = this, e = this.$(this.id + '-' + n);
602		if (e) {
603			this.elements[n] = e;
604			JCommentsInput.prototype.register(e);
605			this.events.add(e, !window.opera && document.all ? 'keydown' : 'keypress', function (e) {
606				return f.keypress(e);
607			});
608		}
609	},
610	error: function (n) {
611		var e = this.elements[n];
612		if (e) {
613			e.focus();
614			var c = e.className.replace('/\berror\b/g', '') + ' error';
615			e.className = c.replace(/\s{2,}/g, ' ');
616		}
617	},
618
619	clear: function (n) {
620		if (n == null) {
621			if (this.form != null) {
622				this.form.reset();
623			}
624			return;
625		}
626		switch (n) {
627			case 'comment':
628				if (this.editor != null) {
629					this.editor.clear();
630				}
631				break;
632			case 'captcha':
633				var cim = this.captchaImage, cin = this.elements['captcha'];
634				if (cim) {
635					var r = new String(Math.floor(Math.random() * 100000));
636					if (/\d+$/g.test(cim.src)) {
637						cim.src = cim.src.replace(/\d+$/g, r);
638					} else if (/\?/g.test(cim.src)) {
639						cim.src = cim.src + '&r=' + r;
640					} else {
641						cim.src = cim.src + '?r=' + new String(Math.floor(Math.random() * 100000));
642					}
643				}
644				if (cin) {
645					cin.value = '';
646				}
647				break;
648			default:
649				var e = this.elements[n];
650				if (e) {
651					e.value = '';
652				}
653				break;
654		}
655	},
656	focus: function (n) {
657		var e;
658		if (n == null) {
659			for (var nm in this.elements) {
660				e = this.elements[nm];
661				if (e) {
662					e.focus();
663					break;
664				}
665			}
666		} else {
667			e = this.elements[n];
668			if (e) {
669				e.focus();
670			}
671		}
672	},
673	keypress: function (e) {
674		if (e.ctrlKey && (e.keyCode == 13 || (e.type == 'keypress' && e.keyCode == 10))) {
675			this.submit();
676			e.returnValue = false;
677			return this.events.cancel(e);
678		}
679		return this.keypressed(e);
680	},
681	add: function (n, i, v) {
682		if (this.form != null) {
683			var e = document.createElement('input');
684			e.setAttribute('type', 'hidden');
685			e.setAttribute('name', n);
686			e.setAttribute('id', i);
687			e.setAttribute('value', v);
688			this.form.appendChild(e);
689		}
690	},
691	remove: function (i) {
692		var e = this.$(i);
693		if (e) {
694			e.value = 0;
695			e.parentNode.removeChild(e);
696		}
697	},
698	setText: function (n, t) {
699		if (n == 'comment') {
700			if (this.editor != null) {
701				this.editor.clear();
702				this.editor.insertText(t);
703			}
704		} else {
705			var e = this.elements[n];
706			if (e) {
707				e.value = t;
708			}
709		}
710	},
711	insertText: function (n, t) {
712		if (n == 'comment') {
713			if (this.editor != null) {
714				this.editor.insertText(t);
715			}
716		} else {
717			var e = this.elements[n];
718			if (e) {
719				e.value += t;
720			}
721		}
722	},
723	storeValues: function () {
724		for (var i = 0; i < this.store.length; i++) {
725			try {
726				var el = JComments.prototype.$(this.id + '-' + this.store[i]);
727				if (el) {
728					JComments.prototype.setCookie(this.store[i], encodeURIComponent(el.value), 14);
729				}
730			} catch (e) {
731			}
732		}
733	},
734	restoreValues: function () {
735		for (var i = 0; i < this.store.length; i++) {
736			try {
737				var el = JComments.prototype.$(this.id + '-' + this.store[i]);
738				if (el) {
739					if (el.type && el.type == 'hidden') {
740						return;
741					} else {
742						el.value = decodeURIComponent(JComments.prototype.getCookie(this.store[i]));
743					}
744				}
745			} catch (e) {
746			}
747		}
748	},
749	submit: function () {
750	},
751	keypressed: function (e) {
752	}
753};
754
755JCommentsIndicator.prototype = {
756	e: null,
757	init: function () {
758		if (this.e == null) {
759			this.e = document.createElement('div');
760			this.e.className = 'busy';
761		}
762	},
763	move: function (p, b) {
764		if (p) {
765			if (this.e.parentNode) {
766				this.e.parentNode.removeChild(this.e);
767			}
768			if (b) {
769				p.insertBefore(this.e, b);
770			} else {
771				p.appendChild(this.e);
772			}
773		}
774	},
775	show: function () {
776		this.e.style.display = 'block';
777	},
778	hide: function () {
779		this.e.style.display = 'none';
780	},
781	start: function (p, b) {
782		this.move(p, b);
783		this.show();
784	},
785	stop: function () {
786		this.hide();
787	}
788};
789
790JComments.prototype = {
791	oi: null,
792	og: null,
793	requestURI: '',
794	busy: null,
795	form: null,
796	cache: {},
797	mode: 'add',
798	readyList: [],
799	isReady: false,
800
801	init: function (oi, og, r) {
802		var ua = navigator.userAgent.toLowerCase();
803		this.browser = {
804			safari: /webkit/.test(ua),
805			opera: /opera/.test(ua),
806			msie: /msie/.test(ua) && !(/opera/.test(ua)),
807			mozilla: /mozilla/.test(ua) && !(/(compatible|webkit)/.test(ua))
808		};
809		this.oi = oi;
810		this.og = og;
811		this.busy = new JCommentsIndicator();
812		this.requestURI = r;
813		var th = this;
814		jtajax.startLoading = function () {
815			th.busy.show();
816		};
817		jtajax.finishLoading = function () {
818			th.busy.hide();
819		};
820	},
821	reinit: function (oi, og) {
822		this.oi = oi;
823		this.og = og;
824		var foi = this.$('object_id');
825		if (foi) {
826			foi.value = oi;
827		}
828		var fog = this.$('object_group');
829		if (fog) {
830			fog.value = og;
831		}
832		this.showPage(oi, og, 0);
833	},
834	setForm: function (f) {
835		this.form = f;
836		this.form_id = f.id;
837		this.setMode('add', null);
838		var jc = this;
839		this.form.submit = function () {
840			jc.saveComment();
841		};
842		this.form.keypressed = function (e) {
843			if (e.keyCode == 27 && jc.mode == 'reply') {
844				jc.restoreForm(false);
845			}
846		};
847		this.formLoaded();
848	},
849	setList: function (l) {
850		this.list_id = l;
851	},
852	setMode: function (m, i) {
853		var b = this.$('comments-form-cancel'), jc = this;
854		if (b != null) {
855			//b.style.display = (m != 'add') ? '' : 'none';
856			b.onclick = (m == 'edit' ? function () {
857				jc.cancelEdit(i);
858			} : (m == 'reply' ? function () {
859				jc.cancelReply();
860			} : null));
861		}
862		this.mode = m;
863	},
864	$: function (id) {
865		if (!id) {
866			return null;
867		}
868		var e = document.getElementById(id);
869		if (!e && document.all) {
870			e = document.all[id];
871		}
872		return e;
873	},
874	ajax: function (func, args, formId) {
875		var response, prevURI = '';
876
877		try {
878			prevURI = jtajax.options.url;
879			jtajax.setup({ url: this.requestURI });
880			response = jtajax.call(func, args, 'post', formId);
881			jtajax.options.url = prevURI;
882		} catch (e) {
883			jtajax.options.url = prevURI;
884		}
885		return response;
886	},
887	initOnReady: function () {
888		if (this.isReadyInited) return;
889		this.isReadyInited = 1;
890		var jc = this;
891		if (this.browser.mozilla || this.browser.opera) {
892			JCommentsEvents.prototype.add(document, 'DOMContentLoaded', jc.ready);
893		} else if (this.browser.msie) {
894			(function () {
895				try {
896					document.documentElement.doScroll('left');
897				} catch (e) {
898					setTimeout(arguments.callee, 50);
899					return;
900				}
901				jc.ready();
902			})();
903		} else if (this.browser.safari) {
904			(function () {
905				if (jc.isReady) return;
906				if (document.readyState != "loaded" && document.readyState != "complete") {
907					setTimeout(arguments.callee, 0);
908					return;
909				}
910				jc.ready();
911			})();
912		}
913		JCommentsEvents.prototype.add(window, 'load', function () {
914			jc.ready(jc);
915		});
916	},
917	onReady: function (f) {
918		if (this.isReady) {
919			f();
920		} else {
921			var jc = this;
922			jc.readyList.push(f);
923			jc.initOnReady();
924		}
925	},
926	ready: function () {
927		var jc = window.jcomments;
928		if (jc.isReady || jc.readyList == null) return;
929		jc.isReady = 1;
930		for (var i = 0, len = jc.readyList.length; i < len; i++) {
931			try {
932				jc.readyList[i]();
933			} catch (e) {
934			}
935		}
936		jc.readyList = null;
937	},
938	setAntiCache: function (c, p, f) {
939		this.aca = c;
940		this.acp = p;
941		this.acf = f;
942		this.onReady(this.loadComments);
943	},
944	loadComments: function () {
945		var jc = window.jcomments;
946		var l = document.location.href, lc = true, i = l.lastIndexOf('#comment-');
947		jc.clear('captcha');
948		if (jc.aca) {
949			if (i != 0) {
950				var c = l.substring(i + 9, l.length);
951				if (!isNaN(c)) {
952					lc = false;
953					jc.showComment(c);
954				}
955			}
956		}
957		if (jc.acp) {
958			if (lc) {
959				jc.showPage(jc.oi, jc.og, 0);
960			}
961		}
962		if (jc.acf) {
963			if (l.lastIndexOf('#addcomments') != -1) {
964				jc.showForm(jc.oi, jc.og, 'comments-form-link');
965			}
966		}
967	},
968	setCookie: function (n, v, d) {
969		var e = '';
970		if (d) {
971			var dt = new Date();
972			dt.setTime(dt.getTime() + (d * 24 * 60 * 60 * 1000));
973			e = "; expires=" + dt.toGMTString();
974		}
975		document.cookie = "jc_" + n + "=" + v + e + "; path=/";
976	},
977	getCookie: function (n) {
978		var re = new RegExp("(\;|^)[^;]*(" + "jc_" + n + ")\=([^;]*)(;|$)");
979		var r = re.exec(document.cookie);
980		return r != null ? r[3] : '';
981	},
982	removeCookie: function (n) {
983		this.setCookie(n, "", -1);
984	},
985	scrollTo: function (n) {
986		var e = this.$(n);
987		if (e) {
988			JCommentsScroll.scroll(e);
989		}
990	},
991	scrollToList: function () {
992		this.scrollTo(this.list_id);
993	},
994	scrollToForm: function () {
995		this.scrollTo(this.form_id);
996	},
997	scrollToComment: function (id) {
998		this.scrollTo('comment-' + id);
999	},
1000	moveElement: function (e, p, b) {
1001		if (e) {
1002			if (p) {
1003				if (e.parentNode) {
1004					e.parentNode.removeChild(e);
1005				}
1006				if (b) {
1007					p.insertBefore(e, b);
1008				} else {
1009					p.appendChild(e);
1010				}
1011			}
1012		}
1013	},
1014	createElement: function (tag, id, className) {
1015		var e = document.createElement(tag);
1016		if (id) {
1017			e.setAttribute('id', id);
1018		}
1019		if (className) {
1020			e.className = className;
1021		}
1022		return e;
1023	},
1024	fade: function (id, s, e, m) {
1025		var speed = Math.round(m / 100), timer = 0;
1026		if (s > e) {
1027			for (var i = s; i >= e; i--) {
1028				setTimeout("JComments.prototype.setOpacity('" + id + "'," + i + ")", (timer * speed));
1029				timer++;
1030			}
1031			var o = JComments.prototype.$(id);
1032			if (o) {
1033				setTimeout(function () {
1034					o.style.display = 'none';
1035				}, ((s - e) * speed));
1036			}
1037		} else if (s < e) {
1038			for (var i = s; i <= e; i++) {
1039				setTimeout("JComments.prototype.setOpacity('" + id + "'," + i + ")", (timer * speed));
1040				timer++;
1041			}
1042		}
1043	},
1044	setOpacity: function (id, opacity) {
1045		var e = this.$(id);
1046		if (e) {
1047			var s = e.style;
1048			s.opacity = (opacity / 100);
1049			s.MozOpacity = (opacity / 100);
1050			s.KhtmlOpacity = (opacity / 100);
1051			s.filter = "alpha(opacity=" + opacity + ")";
1052		}
1053	},
1054	clear: function (n) {
1055		if (this.form != null) {
1056			this.form.clear(n);
1057		}
1058	},
1059	insertText: function (t) {
1060		if (this.form != null) {
1061			this.form.insertText('comment', t);
1062		} else {
1063			var jc = this;
1064			window.setTimeout(function () {
1065				jc.insertText(t);
1066			}, 500);
1067		}
1068	},
1069	busyList: function () {
1070		if (this.list_id) {
1071			var l = this.$(this.list_id);
1072			if (l) {
1073				this.busy.move(l.parentNode, l);
1074			}
1075		}
1076	},
1077	busyForm: function () {
1078		if (this.form_id) {
1079			var f = this.$(this.form_id);
1080			if (f) {
1081				this.busy.move(f.parentNode, f);
1082			}
1083		}
1084	},
1085	busyComment: function (i) {
1086		this.busy.move(this.$('comment-item-' + i), null);
1087	},
1088	saveComment: function () {
1089		var f = '';
1090		if (this.mode != 'edit') {
1091			f = 'JCommentsAddComment';
1092			this.busyForm();
1093			if (this.form) {
1094				this.form.storeValues();
1095			}
1096			if (this.busy) {
1097				this.busy.show();
1098			}
1099		} else {
1100			f = 'JCommentsSaveComment';
1101			if (this.busy) {
1102				this.busy.show();
1103			}
1104		}
1105		return this.ajax(f, null, this.form_id);
1106	},
1107	saveCommentAsync: function () {
1108		return new Promise((resolve, reject) => {
1109			try {
1110				var response = this.saveComment();
1111				resolve(response);
1112			} catch (e) {
1113				reject(e);
1114			}
1115		});
1116	},
1117	editComment: function (i) {
1118		this.busyComment(i);
1119		var a = arguments;
1120		if (this.form == null) {
1121			a = new Array(i, 1);
1122		}
1123		return this.ajax('JCommentsEditComment', a);
1124	},
1125	cancelEdit: function (i) {
1126		if ((!this.cache[i]) || (this.cache[i] == '')) {
1127			this.$('comment-body-' + i).innerHTML = this.cache[i];
1128			this.cache[i] = '';
1129		}
1130		if (this.form) {
1131			this.form.remove('comment-id-hidden-' + i);
1132			this.restoreForm(true);
1133		}
1134		var t = this.$('comment-toolbar-' + i);
1135		if (t) {
1136			t.style.display = '';
1137		}
1138		this.$('comments-form-cancel').style.display = 'none';
1139		return this.ajax('JCommentsCancelComment', arguments);
1140	},
1141	cancelReply: function () {
1142		if (this.form) {
1143			this.form.remove('comment-parent-id-hidden');
1144			document.querySelector('#comments-form').reset();
1145			this.$('comments-form-cancel').style.display = 'none';
1146			this.restoreForm(false);
1147		}
1148	},
1149	quoteComment: function (i) {
1150		var a = arguments;
1151		if (this.form == null) {
1152			a = new Array(i, 1);
1153		}
1154		return this.ajax('JCommentsQuoteComment', a);
1155	},
1156	publishComment: function (i) {
1157		if (this.form) {
1158			this.restoreForm();
1159		}
1160		this.busyComment(i);
1161		return this.ajax('JCommentsPublishComment', arguments);
1162	},
1163	deleteComment: function (i) {
1164		this.busyComment(i);
1165		return this.ajax('JCommentsDeleteComment', arguments);
1166	},
1167	jump2email: function (i) {
1168		return this.ajax('JCommentsJump2email', arguments);
1169	},
1170	updateList: function (t, m) {
1171		if (this.list_id) {
1172			var l = this.$(this.list_id);
1173			if (!l) {
1174				l = this.$('comments');
1175				m = 'a';
1176			}
1177			switch (m) {
1178				case 'a':
1179					l.innerHTML = l.innerHTML + t;
1180					break;
1181				case 'p':
1182					l.innerHTML = t + l.innerHTML;
1183					break;
1184				case 'r':
1185					l.parentNode.innerHTML = t;
1186					break;
1187			}
1188		}
1189	},
1190	updateTree: function (t, r, m) {
1191		var l;
1192		if (r == null) {
1193			l = this.$('comments');
1194			if (l) {
1195				l.innerHTML = t;
1196			}
1197			return;
1198		}
1199		l = this.$('comments-list-' + r);
1200		if (!l) {
1201			var p = this.$('comment-item-' + r);
1202			if (p) {
1203				this.busyComment(r);
1204				l = this.createElement('div', 'comments-list-' + r, 'comments-list');
1205				l.innerHTML = t;
1206				p.parentNode.insertBefore(l, p.nextSibling);
1207			}
1208		} else {
1209			l.innerHTML = (m == 'b' ? t + l.innerHTML : l.innerHTML + t);
1210		}
1211		this.restoreForm(true);
1212	},
1213	updateComment: function (id, t) {
1214		if (t == '') {
1215			var c = this.$('comment-item-' + id);
1216			c.parentNode.removeChild(c);
1217			var l = this.$('comments-list-' + id);
1218			if (l) {
1219				l.parentNode.removeChild(l);
1220			}
1221			return;
1222		}
1223		this.$('comment-item-' + id).innerHTML = t;
1224		var te = this.$('comment-toolbar-' + id);
1225		if (te) {
1226			te.style.display = '';
1227		}
1228		if (this.form) {
1229			this.form.remove('comment-id-hidden-' + id);
1230			this.restoreForm(true);
1231		}
1232	},
1233	voteComment: function (i) {
1234		var v = this.$('comment-vote-holder-' + i);
1235		if (v) {
1236			v.innerHTML = '';
1237			this.busy.start(v, null);
1238		}
1239		return this.ajax('JCommentsVoteComment', arguments);
1240	},
1241	updateVote: function (i, t) {
1242		this.busy.stop();
1243		var c = this.$('comment-vote-holder-' + i);
1244		if (c) {
1245			c.innerHTML = t;
1246		}
1247	},
1248	showComment: function (id) {
1249		return this.ajax('JCommentsShowComment', arguments);
1250	},
1251	showPage: function (i, g, p) {
1252		if (this.form) {
1253			this.restoreForm();
1254		}
1255		var l = this.$(this.list_id);
1256		if (!l) {
1257			l = this.$(this.list_id + '-0');
1258			if (l) {
1259				this.list_id = this.list_id + '-0';
1260			}
1261		}
1262		this.busyList();
1263		return this.ajax('JCommentsShowPage', arguments);
1264	},
1265	showForm: function (i, g, t) {
1266		if (this.form) {
1267			this.moveElement(this.form.form, this.$(t));
1268			return;
1269		}
1270		this.busyForm();
1271		return this.ajax('JCommentsShowForm', arguments);
1272	},
1273	showEdit: function (id, n, e, h, t, txt) {
1274		var jc = this;
1275		if (this.form == null) {
1276			window.setTimeout(function () {
1277				jc.showEdit(id, n, e, h, t, txt);
1278			}, 500);
1279			return;
1280		}
1281		if ((!this.cache[id]) || (this.cache[id] == '')) {
1282			this.cache[id] = this.$('comment-body-' + id).innerHTML;
1283		}
1284		this.busy.stop();
1285		var f = this.form, ff = this.form.form, c = this.$('comment-item-' + id);
1286		if (ff != null && c != null) {
1287			f.add('id', 'comment-id-hidden-' + id, id);
1288			f.setText('name', n);
1289			f.setText('email', e);
1290			f.setText('homepage', h);
1291			f.setText('title', t);
1292			f.setText('comment', txt);
1293			var d = this.$('comments-inline-edit');
1294			if (d) {
1295				d.parentNode.removeChild(d);
1296			} else {
1297				d = this.createElement('div', 'comments-inline-edit', 'border rounded border-top-0 comments-inline-edit');
1298			}
1299			c.appendChild(d);
1300			this.moveElement(ff, d);
1301			this.setMode('edit', id);
1302			var te = this.$('comment-toolbar-' + id);
1303			if (te) {
1304				te.style.display = 'none';
1305			}
1306			this.$('comments-form-cancel').style.display = 'inline-block';
1307			this.scrollTo('comments-inline-edit');
1308			this.form.focus('comment');
1309		}
1310	},
1311	showReply: function (id, q) {
1312		this.busyComment(id);
1313		this.cancelReport();
1314		var jc = this, c = this.$('comment-item-' + id), d = this.$('comments-inline-edit');
1315		if (d) {
1316			d.parentNode.removeChild(d);
1317		} else {
1318			d = this.createElement('div', 'comments-inline-edit', 'border rounded border-top-0 comments-inline-edit');
1319		}
1320		c.appendChild(d);
1321		if (!this.form) {
1322			var t = 'comments-inline-edit', h = this.$('comments-form-link');
1323			if (h) {
1324				t = 'comments-form-link';
1325			}
1326			this.showForm(this.oi, this.og, t);
1327			var pid = id;
1328			this.formLoaded = function () {
1329				var f = jc.form;
1330				if (f != null) {
1331					f.add('parent', 'comment-parent-id-hidden', pid);
1332				}
1333				jc.setMode('reply', pid);
1334				jc.moveElement(jc.form.form, jc.$('comments-inline-edit'));
1335				jc.form.focus();
1336				if (q) {
1337					jc.quoteComment(id);
1338				}
1339			};
1340		} else {
1341			var f = this.form, ff = this.form.form, p = this.$('comment-parent-id-hidden');
1342			if (ff != null && c != null) {
1343				if (!p) {
1344					f.add('parent', 'comment-parent-id-hidden', id);
1345				} else {
1346					p.value = id;
1347				}
1348				this.moveElement(ff, d);
1349				this.setMode('reply', id);
1350				this.form.focus();
1351				if (q) {
1352					this.quoteComment(id);
1353				}
1354			}
1355		}
1356		this.$('comments-form-cancel').style.display = 'inline-block';
1357	},
1358	formLoaded: function () {
1359	},
1360	restoreForm: function (c) {
1361		var f = this.form;
1362		if (f != null) {
1363			var ff = this.form.form;
1364			this.busy.stop();
1365			if (ff != null) {
1366				if (c) {
1367					f.clear(null);
1368				}
1369				f.restoreValues();
1370				var a = this.$('addcomments'), p = this.$('comment-parent-id-hidden');
1371				if (p) {
1372					p.value = 0;
1373				}
1374				this.moveElement(ff, a.parentNode, a);
1375				var d = this.$('comments-inline-edit');
1376				if (d) {
1377					d.parentNode.removeChild(d);
1378				}
1379				this.setMode('add', null);
1380			}
1381		}
1382	},
1383	hideChildComments: function (e, id) {
1384		var b = this.$('show-button-' + id);
1385		var c = this.$('comment-item-' + id);
1386		b.style.display = '';
1387		c.classList.add('hide-children');
1388		e.style.display = 'none';
1389		return false;
1390	},
1391	showChildComments: function (e, id) {
1392		var b = this.$('hide-button-' + id);
1393		var c = this.$('comment-item-' + id);
1394		b.style.display = '';
1395		c.classList.remove('hide-children');
1396		e.style.display = 'none';
1397		return false;
1398	},
1399	reportComment: function (id) {
1400		this.busyComment(id);
1401		this.cancelReply();
1402		var c = this.$('comment-item-' + id), d = this.$('comments-inline-report');
1403		if (d) {
1404			d.parentNode.removeChild(d);
1405		} else {
1406			d = this.createElement('div', 'comments-inline-report', 'comments-inline-report');
1407		}
1408		c.appendChild(d);
1409		var a = new Array(id, 'comments-inline-report');
1410		return this.ajax('JCommentsShowReportForm', a);
1411	},
1412	saveReport: function () {
1413		this.ajax('JCommentsReportComment', null, 'comments-report-form');
1414
1415		return true;
1416	},
1417	cancelReport: function () {
1418		var div = document.querySelector('#comments-inline-report');
1419
1420		if (div) {
1421			div.innerHTML = '';
1422		}
1423	},
1424	closeReport: function (m) {
1425		this.cancelReport();
1426
1427		if (m) {
1428			this.showMessage(m, 'success', 'comments-inline-report');
1429		}
1430	},
1431	banIP: function (id) {
1432		this.ajax('JCommentsBanIP', arguments)
1433	},
1434	error: function (m, t, n) {
1435		if (!t || t == '') {
1436			t = this.form_id;
1437		}
1438
1439		// TODO Place at the current form position
1440		//Joomla.renderMessages({'error': [m]}, '#comments-report-form-msg');
1441
1442		this.showMessage(m, 'danger', t);
1443
1444		if (this.form != null) {
1445			this.form.error(n);
1446		}
1447	},
1448	message: function (m, t) {
1449		if (!t || t == '') {
1450			t = this.form_id;
1451		}
1452
1453		//Joomla.renderMessages({'info': [m]}, '#comments-report-form-msg');
1454		this.showMessage(m, 'success', t);
1455	},
1456	showMessage: function (m, c, t) {
1457		clearTimeout(this.fadeTimer);
1458		var fe = this.$('comments-form-message');
1459		var af = this.$(t);
1460		if (fe) {
1461			fe.parentNode.removeChild(fe);
1462		}
1463		fe = JComments.prototype.createElement('div', 'comments-form-message', '');
1464		if (af) {
1465			JComments.prototype.moveElement(fe, af, af.firstChild);
1466		} else {
1467			alert(m);
1468			return;
1469		}
1470		if (!c) {
1471			c = 'info';
1472		}
1473		fe.className = 'alert alert-' + c;
1474		fe.role = 'alert';
1475		fe.innerHTML = m;
1476		fe.style.display = 'block';
1477		JComments.prototype.setOpacity(fe.id, 100);
1478		this.fadeTimer = setTimeout(function () {
1479			JComments.prototype.fade('comments-form-message', 100, 0, 1000);
1480		}, 6000);
1481		JCommentsScroll.scroll(fe);
1482	},
1483	go: function (l) {
1484		window.open(l);
1485		return false;
1486	}
1487};
1488
1489document.addEventListener('DOMContentLoaded', function () {
1490	document.body.addEventListener('click', async function (e) {
1491		if (e.target && e.target.id == 'addcomments') {
1492			e.preventDefault();
1493			var el = e.target;
1494			jcomments.showForm(el.dataset.object_id, el.dataset.object_group, 'comments-form-link');
1495		} else if (e.target && e.target.id == 'comments-form-send') {
1496			e.preventDefault();
1497			try {
1498				await jcomments.saveCommentAsync();
1499				var jc = window.jcomments;
1500				if (jc) {
1501					jc.showPage(jc.oi, jc.og, 0);
1502				}
1503			} catch (error) {
1504				console.error('Error saving comment:', error);
1505			}
1506		} else if (e.target && e.target.id == 'comments-form-reset') {
1507			e.preventDefault();
1508
1509			document.querySelector('#comments-form').reset();
1510		} else if (e.target && (e.target.id == 'comments-form-captcha-image' || e.target.id == 'cmd-captcha-reload')) {
1511			e.preventDefault();
1512			jcomments.clear('captcha');
1513		}
1514	});
1515
1516	const subscribeButton = document.querySelector('.cmd-subscribe');
1517	if (subscribeButton) {
1518		subscribeButton.addEventListener('click', function (e) {
1519			e.preventDefault();
1520			let href = this.getAttribute('href');
1521			Joomla.request({
1522				url: href + '&format=json',
1523				onSuccess: (response) => {
1524					let _response = JSON.parse(response);
1525					if (_response.success) {
1526						this.setAttribute('href', _response.data.href);
1527						this.setAttribute('title', _response.data.title);
1528						this.innerHTML = '<span aria-hidden="true" class="icon-mail icon-fw"></span> ' + _response.data.title;
1529						Joomla.renderMessages({ 'message': [_response.message] }, '.comments-list-footer');
1530					} else {
1531						Joomla.renderMessages({ 'warning': [_response.message] }, '.comments-list-footer');
1532					}
1533				},
1534				onError: function (xhr) {
1535					let response = JSON.parse(xhr.responseText);
1536					Joomla.renderMessages({ 'error': [response.message] }, '.comments-list-footer');
1537				}
1538			});
1539		});
1540	}
1541});

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.