PageSourceSearch

https://www.liederabend.cat/components/com_jlexcomment/assets/script.js?v=3.7.3

js liederabend.cat collected 2026-10-02 13:11:54 UTC 126,503 bytes, 4,231 lines download raw bytes

1function jlexcomment($, config, settings)
2{
3	var _this = this,
4		config = config || {};
5
6	this.config = {
7		key : null,
8		sort : 'best',
9		timestamp : 0,
10		box : null,
11		id : 0,
12		request : '/component/jlexcomment',
13		page_comment: 1,
14		timestamp_offset : 0,
15		parent_id: 0
16	};
17
18	this.browser = {
19		contenteditable : null,
20		guest : {
21			name : '',
22			email : ''
23		}
24	};
25
26	this.timestamp = {};
27	this.tmpCache = {};
28	this.tpl = {};
29
30	// public protocols
31	String.prototype.hexEncode = function(){
32	    var hex, i;
33
34	    var result = "";
35	    for (i=0; i<this.length; i++) {
36	        hex = this.charCodeAt(i).toString(16);
37	        result += ("000"+hex).slice(-4);
38	    }
39
40	    return result
41	}
42
43	// reset configuration
44	$.each(_this.config, function(k,v)
45	{
46		if (config.hasOwnProperty(k))
47		{
48			_this.config[k] = config[k];
49		}
50	});
51
52	// lib of readmore
53	// lib of readmore
54	if (settings.readmore==1)
55	{
56		!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){"use strict";function e(t,e,i){var o;return function(){var n=this,a=arguments,s=function(){o=null,i||t.apply(n,a)},r=i&&!o;clearTimeout(o),o=setTimeout(s,e),r&&t.apply(n,a)}}function i(t){var e=++h;return String(null==t?"rmjs-":t)+e}function o(t){var e=t.clone().css({height:"auto",width:t.width(),maxHeight:"none",overflow:"hidden"}).insertAfter(t),i=e.outerHeight(),o=parseInt(e.css({maxHeight:""}).css("max-height").replace(/[^-\d\.]/g,""),10),n=t.data("defaultHeight");e.remove();var a=o||t.data("collapsedHeight")||n;t.data({expandedHeight:i,maxHeight:o,collapsedHeight:a}).css({maxHeight:"none"})}function n(t){if(!d[t.selector]){var e=" ";t.embedCSS&&""!==t.blockCSS&&(e+=t.selector+" + [data-readmore-toggle], "+t.selector+"[data-readmore]{"+t.blockCSS+"}"),e+=t.selector+"[data-readmore]{transition: height "+t.speed+"ms;overflow: hidden;}",function(t,e){var i=t.createElement("style");i.type="text/css",i.styleSheet?i.styleSheet.cssText=e:i.appendChild(t.createTextNode(e)),t.getElementsByTagName("head")[0].appendChild(i)}(document,e),d[t.selector]=!0}}function a(e,i){this.element=e,this.options=t.extend({},r,i),n(this.options),this._defaults=r,this._name=s,this.init(),window.addEventListener?(window.addEventListener("load",c),window.addEventListener("xresize",c)):(window.attachEvent("load",c),window.attachEvent("resize",c))}var s="readmore",r={speed:100,collapsedHeight:200,heightMargin:16,moreLink:'<a href="#">Read More</a>',lessLink:'<a href="#">Close</a>',embedCSS:!0,blockCSS:"display: block; width: 100%;",startOpen:!1,blockProcessed:function(){},beforeToggle:function(){},afterToggle:function(){}},d={},h=0,c=e(function(){t("[data-readmore]").each(function(){var e=t(this),i="true"===e.attr("data-expanded");o(e),e.css({height:e.data(i?"expandedHeight":"collapsedHeight")})})},100);a.prototype={init:function(){var e=t(this.element);e.data({defaultHeight:this.options.collapsedHeight,heightMargin:this.options.heightMargin}),o(e);var n=e.data("collapsedHeight"),a=e.data("heightMargin");if(e.outerHeight(!0)<=n+a)return this.options.blockProcessed&&"function"==typeof this.options.blockProcessed&&this.options.blockProcessed(e,!1),!0;var s=e.attr("id")||i(),r=this.options.startOpen?this.options.lessLink:this.options.moreLink;e.attr({"data-readmore":"","data-expanded":this.options.startOpen,id:s}),e.after(t(r).on("click",function(t){return function(i){t.toggle(this,e[0],i)}}(this)).attr({"data-readmore-toggle":s,"aria-controls":s})),this.options.startOpen||e.css({height:n}),this.options.blockProcessed&&"function"==typeof this.options.blockProcessed&&this.options.blockProcessed(e,!0)},toggle:function(e,i,o){o&&o.preventDefault(),e||(e=t('[aria-controls="'+this.element.id+'"]')[0]),i||(i=this.element);var n=t(i),a="",s="",r=!1,d=n.data("collapsedHeight");n.height()<=d?(a=n.data("expandedHeight")+"px",s="lessLink",r=!0):(a=d,s="moreLink"),this.options.beforeToggle&&"function"==typeof this.options.beforeToggle&&this.options.beforeToggle(e,n,!r),n.css({height:a}),n.on("transitionend",function(i){return function(){i.options.afterToggle&&"function"==typeof i.options.afterToggle&&i.options.afterToggle(e,n,r),t(this).attr({"data-expanded":r}).off("transitionend")}}(this)),t(e).replaceWith(t(this.options[s]).on("click",function(t){return function(e){t.toggle(this,i,e)}}(this)).attr({"data-readmore-toggle":n.attr("id"),"aria-controls":n.attr("id")}))},destroy:function(){t(this.element).each(function(){var e=t(this);e.attr({"data-readmore":null,"data-expanded":null}).css({maxHeight:"",height:""}).next("[data-readmore-toggle]").remove(),e.removeData()})}},t.fn.readmore=function(e){var i=arguments,o=this.selector;return e=e||{},"object"==typeof e?this.each(function(){if(t.data(this,"plugin_"+s)){var i=t.data(this,"plugin_"+s);i.destroy.apply(i)}e.selector=o,t.data(this,"plugin_"+s,new a(this,e))}):"string"==typeof e&&"_"!==e[0]&&"init"!==e?this.each(function(){var o=t.data(this,"plugin_"+s);o instanceof a&&"function"==typeof o[e]&&o[e].apply(o,Array.prototype.slice.call(i,1))}):void 0}});
57	}
58
59	this.box = this.config.box==null ? null : $(this.config.box);
60
61	this.dialog = function(options)
62	{
63		var _dialog = this,
64			settings = 
65			{
66				caption 	: _this.lang.get('dialog'),
67				submitLabel : _this.lang.get('submit'),
68				cancelLabel : _this.lang.get('cancel'),
69				content 	: '',
70				loadfn 		: null,
71				submitfn 	: null,
72				cancelfn 	: null
73			};
74
75		if(typeof options=='object') $.extend(settings, options);
76
77		_dialog.init = function()
78		{
79			var html = '<div class="jcm-overlay">';
80					html+= '<div class="jcm-dialog">';
81						html+= '<div class="jcm-dg-caption">'+settings.caption+'</div>';
82						html+= '<div class="jcm-dg-error"></div>';
83						html+= '<div class="jcm-dg-content">'+settings.content+'</div>';
84						html+= '<div class="jcm-dg-footer">';
85							if (settings.submitLabel!==false)
86							{
87								html+= '<button class="jcm-dg-submit">'+settings.submitLabel+'</button>';
88							}
89							html+= '<button class="jcm-dg-cancel">'+settings.cancelLabel+'</button>';
90						html+= '</div>';
91					html+= '</div>';
92				html+= '</div>';
93			_dialog.el = $(html);
94			_dialog.el.appendTo ('body');
95
96			// events
97			if (typeof settings.loadfn=='function')
98				settings.loadfn (_dialog);
99
100			_dialog.el.on('click', '.jcm-dg-submit', function() {
101				if(typeof settings.submitfn=='function')
102					settings.submitfn(_dialog);
103			});
104
105			_dialog.el.on('click', '.jcm-dg-cancel', function() {
106				if(typeof settings.cancelfn=='function')
107				{
108					var rn = settings.cancelfn (_dialog);
109					if (rn!==false)
110					{
111						_dialog.off ();
112					}
113				} else {
114					_dialog.off ();
115				}
116			});
117
118			var resizeEvent = function ()
119			{
120				if (! $('.jcm-dialog').length)
121				{
122					return false;
123				}
124
125				var widthOfScreen = $(window).width (),
126					heightOfScreen = $(window).width ();
127
128				if (widthOfScreen <= 450)
129				{
130					_dialog.el.find ('.jcm-dialog')
131								.removeClass ('wide touch')
132								.removeAttr ('style')
133								.addClass ('touch');
134
135					$('html,body').addClass ('disableScroll');
136				} else {
137					_dialog.el.find ('.jcm-dialog')
138								.removeClass ('wide touch')
139								.removeAttr ('style')
140								.addClass ('wide');
141
142					var widthOfdialog = widthOfScreen > 650 ? 600 : (widthOfScreen-40),
143						left = (widthOfScreen - widthOfdialog) / 2,
144						maxHeight = heightOfScreen - 50 - 30; // 30 is top possition.
145
146					_dialog.el.find ('.jcm-dialog').css ({
147						width: widthOfdialog + 'px',
148						left : left + 'px',
149						'max-height' : maxHeight + 'px'
150					});
151
152					$('html,body').removeClass ('disableScroll');
153				}
154			}
155
156			resizeEvent ();
157			$(window).resize (function(){
158				resizeEvent ();
159			});
160		};
161
162		_dialog.off = function ()
163		{
164			_dialog.el.off ();
165			_dialog.el.fadeOut ('fast', function (){
166				$(this).remove ();
167				$('html,body').removeClass ('disableScroll');
168			});
169		};
170
171		_dialog.setError = function (msg)
172		{
173			_dialog.el.find ('.jcm-dg-error')
174				.addClass('active').html (msg);
175		};
176
177		_dialog.clearError = function ()
178		{
179			_dialog.el.find ('.jcm-dg-error')
180				.removeClass('active').html ('');
181		};
182
183		_dialog.overlay = function ()
184		{
185			if (!_dialog.el.find('.jcm-dg-overlay').length)
186			{
187				_dialog.el.find('.jcm-dg-content').append ('<div class="jcm-dg-overlay"></div>');
188				_dialog.el.find('button').attr ('disabled', 'disabled');
189			}
190		};
191
192		_dialog.unOverlay = function ()
193		{
194			_dialog.el.find('.jcm-dg-overlay').remove ();
195			_dialog.el.find('button').removeAttr ('disabled');
196		};
197
198		_dialog.init ();
199	};
200
201	this.sticker_data = null;
202	this.sticker_found = {};
203	this.sticker = function(options)
204	{
205		var _sticker = this,
206			stCf = {parent:null, selected:null},
207			state = {gid:0, query:''};
208
209		if(typeof options=='object') $.extend(stCf, options);
210
211		this.el = null;
212		this.init = function()
213		{
214			var html = '<div class="jcm-sticker">';
215					html+= '<div class="_header"></div>';
216					html+= '<div class="_content"></div>';
217				html+= '</div>';
218			_sticker.el = $(html);
219
220			if(_this.sticker_data==null)
221			{
222				$.get(_this.helper.url({task:'sticker.group'}), function(d){
223					if (typeof d=='object')
224						_this.sticker_data = d;
225						_sticker.createHeader();
226						_sticker.loadStickers();
227				}, 'json');
228			} else {
229				_sticker.createHeader();
230				_sticker.loadStickers();
231			}
232
233			stCf.parent.empty();
234			_sticker.el.appendTo(stCf.parent);
235			_sticker.events();
236		};
237
238		this.events = function()
239		{
240			_sticker.el.on('click','.jcm-sticker-group a', function(e){
241				e.preventDefault();
242				var gid = $(this).attr('data-id')*1;
243				state.gid = gid;
244				_sticker.loadStickers();
245			});
246
247			// back to home
248			_sticker.el
249			.on('click','.jcm-sticker-home', function(e){
250				e.preventDefault();
251				state.gid = 0;
252				state.query = '';
253				_sticker.el.find('.jcm-sticker-active').parent().remove ();
254				_sticker.el.find('input[type=text]').val('');
255				_sticker.loadStickers();
256			})
257			.on('click', '.jcm-btn-image', function(e){
258				e.preventDefault();
259				var _el = $('<input type="file" style="width:1px;height:1px;overflow:hidden">');
260					_el.appendTo('body');
261				_el.change(function(evt){
262					if(evt.target.files.length!=1 || typeof stCf.selected!='function') return false;
263
264					var oUrl = window.webkitURL||window.URL;
265					stCf.selected(0, oUrl.createObjectURL(evt.target.files[0]), function($imger){
266						var stDt = new FormData();
267						stDt.append('file', evt.target.files[0]);
268
269						var xhr = $.ajax({
270							url: _this.helper.url({task:'sticker.upload'}),
271							data: stDt,
272							processData: false,
273							contentType: false,
274							dataType: 'json',
275							xhr: function(){
276								var xhrobj = $.ajaxSettings.xhr();
277								if(xhrobj.upload) {
278									var prs='<div class="_process_bar">';
279											prs+='<div class="_process_result"><span class="_moved"><span class="_tx">0</span>/100</span></div>';
280										prs+='</div>';
281
282									$imger.find('._stir_loading').append(prs);
283
284							        xhrobj.upload.addEventListener('progress', function(event) {
285									            var percent = 0;
286									            var position = event.loaded || event.position;
287									            var total = event.total;
288									            if(event.lengthComputable)
289									            {
290									                percent = Math.ceil(position / total * 100);
291									            }
292
293									            //Set progress
294									            $imger.find('._process_result').css('width',percent+'%');
295									            $imger.find('._tx').text(percent);
296									        }, false);
297							    }
298								return xhrobj;
299							},
300							type: 'POST',
301							success: function(d){
302								if(d.status==200)
303								{
304									$imger.find('input[name=sticker_id]').val(d.data.id);
305									$imger.find('._stir_loading').fadeOut('fast', function(){
306										$(this).remove();
307									});
308								}
309							}
310						});
311					});
312				});
313				_el.trigger('click');
314			})
315			.on('keypress', 'input[type=text]', function(e){
316				if(e.which==13)
317				{
318					state.query = $(this).val();
319					_sticker.loadStickers();
320					return false;
321				}
322			})
323			.on('click', '.jcm-sticker-id', function(e){
324				e.preventDefault();
325				var id = $(this).attr('data-id') * 1;
326				if(typeof stCf.selected == 'function')
327					stCf.selected(id, $(this).find('img').attr('src'));
328			});
329		};
330
331		this.createHeader = function()
332		{
333			var html = '<ul class="jcm-sticker-gp-hl">';
334					html+= '<li><a href="#" class="jcm-sticker-home"><i class="fas fa-home"></i> '+_this.lang.get('home')+'</a></li>';
335					if(settings.sticker_photo)
336					{
337						html+= '<li><a href="#" class="jcm-btn-image"><i class="fas fa-upload"></i> '+_this.lang.get('use_your_image')+'</a></li>';
338					}
339				html+= '</ul>';
340
341				html+= '<input type="text" placeholder="'+_this.lang.get('search_sticker')+'" />';
342			_sticker.el.find('._header').empty().append(html);
343		};
344
345		this.loadStickers = function()
346		{
347			if(state.gid==0 && /^\s*$/.test(state.query))
348			{
349				// load groups
350				var html = '';
351				if(!_this.sticker_data.length)
352				{
353					html = '<span>'+_this.lang.get('no_sticker_found')+'.</span>';
354				} else {
355					html = '<ul class="jcm-sticker-group">';
356					$.each(_this.sticker_data, function(k,v){
357						html+= '<li><a href="#" data-id="'+v.id+'">'+v.name+'</a></li>';
358					});
359					html+= '</ul>';
360				}
361
362				_sticker.el.find('._content').empty().append(html);
363			} else {
364				state.query = /^\s*$/.test(state.query) ? '' : $.trim(state.query);
365
366				var key = state.gid+'_'+state.query.hexEncode(),
367					bind = function(data)
368					{
369						var html = '';
370						if (typeof data=='object' && data.length)
371						{
372							html+= '<ul class="_list-stickers">';
373							$.each(data, function(k,v){
374								html+= '<li>';
375									html+= '<a href="#" class="jcm-sticker-id" data-id="'+v.id+'">';
376										html+= '<img src="'+v.url+'" alt="" />';
377									html+= '</a>';
378								html+= '</li>';
379							});
380							html+= '</ul>';
381						} else {
382							html = '<span>'+_this.lang.get('no_sticker_found')+'.</span>';
383						}
384						_sticker.el.find('._content').empty().append(html);
385					};
386
387				if(state.query=='')
388				{
389					// add group to header.
390					var group_name = '';
391					$.each(_this.sticker_data, function(k,v){
392						if(v.id==state.gid)
393							group_name=v.name;
394					});
395
396					var group_active = '<li><a href="#" class="jcm-sticker-active">'+group_name+'</a></li>';
397					_sticker.el.find('.jcm-sticker-gp-hl').append(group_active);
398				}
399
400				if(_this.sticker_found.hasOwnProperty(key))
401				{
402					bind(_this.sticker_found[key]);
403				} else {
404					$.get(_this.helper.url({task:'sticker.load'}), {id:state.gid, query:state.query}, function(d){
405						_this.sticker_found[key] = d;
406						bind(_this.sticker_found[key]);
407					}, 'json');
408				}
409			}
410		};
411
412		this.init();
413	};
414
415	this.lang = {
416		data : {},
417		load : function (langs)
418		{
419			_this.lang.data = langs;
420		},
421		get  : function ()
422		{
423			if (! arguments.length) return '';
424
425			if ( _this.lang.data.hasOwnProperty(arguments[0]) )
426			{
427				if (arguments.length==1)
428				{
429					return _this.lang.data[ arguments[0] ];
430				} else {
431					var str = _this.lang.data[ arguments[0] ];
432					for (var i = 1; i <= arguments.length; i++) {
433						str = str.replace(/(\%s)/, arguments[i]);
434					}
435					return str;
436				}
437			}
438			return arguments[0];
439		}
440	};
441
442	this.helper = {
443		url : function(params)
444		{
445			params['t'] = new Date().getTime();
446			return _this.config.request
447					+ (_this.config.request.indexOf('?')==-1?'?':'&')
448					+ $.param (params);
449		},
450		cookie : {
451			set : function(cname, cvalue, exdays)
452			{
453				var d = new Date();
454			    d.setTime(d.getTime() + (exdays*24*60*60*1000));
455			    var expires = "expires="+ d.toUTCString();
456			    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
457			},
458			get : function(cname)
459			{
460				var name = cname + "=";
461			    var decodedCookie = decodeURIComponent(document.cookie);
462			    var ca = decodedCookie.split(';');
463			    for(var i = 0; i <ca.length; i++) {
464			        var c = ca[i];
465			        while (c.charAt(0) == ' ') {
466			            c = c.substring(1);
467			        }
468			        if (c.indexOf(name) == 0) {
469			            return c.substring(name.length, c.length);
470			        }
471			    }
472			    return null;
473			},
474			earse : function(cname)
475			{
476				document.cookie = cname + "=0; expires=Thu, 18 Dec 2013 12:00:00 UTC";
477			}
478		},
479	};
480
481	this.createCmform = function(dest, data, openform)
482	{
483		var form = _this.tpl.form.clone();
484		form.removeAttr("id");
485
486		setTimeout(function(){
487			if(form.width()<=450){
488				form.addClass('jcm-form-xs');
489			}
490		}, 500);
491
492		// bind variables
493		if(typeof data == "object")
494		{
495			// check member or guest
496			if(!data.member)
497			{
498				form.find('#jcm-input-name-field').val(data.guest_name);
499				form.find('#jcm-input-email-field').val(data.guest_email);
500			}
501			delete data.member;
502			delete data.guest_name;
503			delete data.guest_email;
504
505			// lock
506			if(data.locked==1)
507				form.find('[name=locked]').prop('checked', true);
508			delete data.locked;
509
510			$.each(data, function(k,v)
511			{
512				if(v==null||typeof v=='object') return true;
513
514				if(form.find('[name="'+k+'"]').length || form.find('[data-name="'+k+'"]').length )
515				{
516					if(k=='comment' && _this.browser.contenteditable)
517					{
518						form.find('.jcm-textarea').html(v.replace(/\n/g,'<br>'));
519
520						if(typeof twemoji=='object')
521						{
522							twemoji.parse(form.find('.jcm-textarea')[0]);
523						}
524					} else {
525						if(form.find('[name="'+k+'"]').length)
526						{
527							form.find('[name="'+k+'"]').val(v);
528						} else {
529							form.find('[data-name="'+k+'"]').text(v);
530						}
531					}
532					delete data[k];
533				}
534			});
535
536			$.each(data, function(k,v)
537			{
538				if (v==null || typeof v=='object')
539				{
540					return true;
541				}
542
543				var input = $('<input type="hidden" />');
544					input.attr('name', k);
545					input.attr('value', v);
546
547				input.appendTo ( form.find('form') );
548			});
549		}
550
551		_this.createFormEvents(form , data, openform);
552
553		form.appendTo(dest);
554
555		return form;
556	};
557
558	this.emoji = {
559		loaded: false,
560		input: null,
561		init: function(){
562			if(typeof EmojiPanel=="undefined") return;
563			$('#jcm-emoji').appendTo('body');
564
565			ej = new EmojiPanel({
566		        container: '#jcm-emoji',
567		        trigger: '.jcm-uk',
568		        json_url: settings.url_base+'/components/com_jlexcomment/assets/emojis.json'
569		    });
570
571			setTimeout(function(){
572				if(typeof twemoji=='object')
573					twemoji.parse($('#jcm-emoji')[0], {className:"ej"});
574			}, 1000);
575
576		    ej.addListener('select', function(emoji){
577		    	if(_this.emoji.input==null) return;
578
579				_this.emoji.input.focus();
580				if(_this.browser.contenteditable==true)
581				{
582					var sel, range, ejCt='<img draggable="false" class="emoji" alt="'+emoji.char+'" src="https://cdn.jsdelivr.net/gh/jdecked/[email protected]/assets/72x72/'+emoji.unicode+'.png">',
583						node = $(ejCt)[0];
584				    if(window.getSelection){
585				        // IE9 and non-IE
586				        sel = window.getSelection();
587				        if(sel.getRangeAt && sel.rangeCount)
588				        {
589				            range = sel.getRangeAt(0);
590				            range.deleteContents();
591				            range.insertNode(node);
592				            range = range.cloneRange();
593			                range.setStartAfter(node);
594			                range.collapse(true);
595			                sel.removeAllRanges();
596			                sel.addRange(range);
597				        }
598				    } else if (document.selection && document.selection.type!= "Control"){
599				        // IE<9
600				        document.selection.createRange().pasteHTML(ejCt);
601				    }
602				} else {
603					var field = _this.emoji.input[0];
604					//IE support
605				    if(document.selection){
606				        document.selection.createRange().text = emoji.char;
607				    } else if(field.selectionStart || field.selectionStart=='0') {
608				        var startPos = field.selectionStart,
609				        	endPos 	 = field.selectionEnd;
610
611				        field.value = field.value.substring(0, startPos)
612				            + emoji.char
613				            + field.value.substring(endPos, field.value.length);
614				    } else {
615				        field.value+=emoji.char;
616				    }
617				}
618			});
619
620			$('body').on('click', function(e){
621				if(!$(e.target).closest('#jcm-emoji.active').length && !$(e.target).closest('.jcm-btn-emoticon').length){
622					$('#jcm-emoji.active, .jcm-btn-emoticon.active').removeClass('active');
623				}
624			});
625		},
626		toggle: function($btn){
627			if($btn.hasClass('active'))
628			{
629				// hide
630				$btn.removeClass('active');
631				$('#jcm-emoji').removeClass('active');
632			} else {
633				$('.jcm-btn-emoticon').not($btn).removeClass('active');
634				$btn.addClass('active');
635				$('#jcm-emoji').addClass('active');
636				_this.emoji.follow($btn);
637			}
638		},
639		follow: function($btn)
640		{
641			var $ej=$('#jcm-emoji');
642			var ejTop=$btn.offset().top-$ej.height(),
643				ejLeft=$btn.offset().left;
644
645			if(ejLeft+$ej.width()>$(window).width())
646				ejLeft=0;
647
648			$ej.css('left', ejLeft+'px');
649			$ej.css('top', ejTop+'px');
650		}
651	};
652
653	this.styles = null;
654	this.createFormEvents = function(form, cdata, openform)
655	{
656		var html_sticker = function (id, url) {
657				form.find('.jcm-sticker-preview').off();
658				form.find('.jcm-sticker-preview').remove();
659
660				var preview = '<div class="jcm-sticker-preview">';
661						preview+= '<div class="_img_box">';
662							preview+= '<img src="'+url+'" alt="">';
663							if(id==0)
664							{
665								// uploading
666								preview+= '<div class="_stir_loading"></div>';
667							}
668							preview+= '<input type="hidden" name="sticker_id" value="'+id+'" />';
669						preview+= '</div>';
670						preview+= '<div class="clearfix"></div>';
671						preview+= '<a href="#" class="_remove jcm-tooltip" title="'+_this.lang.get('remove')+'"><i class="fas fa-times" style="font-size:20px;
671color:#777"></i></a>';
672					preview+= '</div>';
673
674				// convert to DOM
675				preview = $(preview);
676				preview.on('click', '._remove', function(e){
677					e.preventDefault();
678					preview.off();
679					preview.remove();
680				});
681				
682				form.find('.jcm-input-cm').after (preview);
683
684				return preview;
685			},
686			html_media = function (file, state)
687			{
688				var state = typeof state=='undefined' ? '_rlt_process' : state,
689					getExtension = function (name)
690					{
691						var result = name.match (/\.([A-z0-9]+)$/);
692						if (result == null)
693						{
694							return 'unknown';
695						}
696						return result[1];
697					},
698					formatSize = function(size) {
699						if (size>1000*1000*1000) {
700							size = parseInt(size/(1000*1000*1000)) + ' Gb';
701						} else if (size>1000*1000) {
702							size = parseInt(size/(1000*1000)) + ' Mb';
703						} else {
704							size = parseInt(size/1000) + ' Kb';
705						}
706						return size;
707					},
708					preview = '<div class="jcm-media-preview '+state+'">';
709						preview+= '<span class="jcm-ext _ext_">'+getExtension(file.name)+'</span>';
710						preview+= '<div class="jcm-info">';
711							preview+= '<span class="_caption">'+file.name+'</span>';
712							preview+= '<span class="_size">'+formatSize(file.fileSize)+'</span>';
713
714							// edit task
715							preview+= '<a href="#" class="_edit">'+_this.lang.get('edit')+'</a>';
716
717							// error msg
718							preview+= '<div class="_error"></div>';
719
720							// process box
721							preview+= '<div class="_process_cont">';
722								preview+= '<div class="_process_box">';
723									preview+= '<div class="_process_bar"></div>';
724								preview+= '</div>';
725								preview+= '<span class="_process_text"><span class="_process_result">0</span>/100%</span>';
726							preview+= '</div>';
727
728							preview+= '<span class="_desc">'+file.description+'</span>';
729
730							// form to edit
731							preview+= '<div class="_form_edit">';
732								preview+= '<span class="_form_error"></span>';
733								preview+= '<label>'+_this.lang.get('caption')+'</label>';
734								preview+= '<input type="text" />';
735								preview+= '<label>'+_this.lang.get('description')+'</label>';
736								preview+= '<textarea></textarea>';
737								preview+= '<button type="button" class="jcm-button-hl _submit_edit">'+_this.lang.get('update')+'</button>';
738								preview+= '<button type="button" class="jcm-button _cancel_edit">'+_this.lang.get('cancel')+'</button>';
739							preview+= '</div>';
740							
741							preview+= '<div class="_task">';
742								preview+= '<a href="#" class="_remove fas fa-times jcm-tooltip" style="font-size:20px" title="'+_this.lang.get('remove')+'"></a>';
743								preview+= '<a href="#" class="_cancel fas fa-times jcm-tooltip" style="font-size:20px" title="'+_this.lang.get('cancel')+'"></a>';
744							preview+= '</div>';
745						preview += '</div>';
746						preview += '<div class="clearfix"></div>';
747						preview += '<input type="hidden" class="_media_id" name="media_cid[]" value="'+(file.hasOwnProperty('id')?file.id:'')+'" />';
748					preview+= '</div>';
749
750				// convert to DOM
751				preview = $(preview);
752				preview.on('click', '._remove', function(e){
753					e.preventDefault();
754					preview.off();
755					preview.remove();
756
757					if (!form.find('.jcm-media-preview').length)
758					{
759						form.find('._media_box').remove();
760					}
761				})
762				.on('click', '._edit', function(e){
763					e.preventDefault();
764					preview.removeClass ('_rlt_completed')
765							.addClass ('_rlt_editing');
766
767					preview.find ('input[type=text]').val ( preview.find('._caption').text() );
768					
769					var desc = preview.find('._desc').text();
770					preview.find ('textarea').val ( desc.replace(/<br\s*[\/]?>/gi,"\n") );
771				})
772				.on ('click', '._submit_edit', function(e){
773					e.preventDefault();
774					var data = {
775						id : preview.find ('._media_id').val()*1,
776						name: preview.find ('input[type=text]').val(),
777						description: preview.find ('textarea').val()
778					};
779
780					if (/^\s*$/.test(data.name))
781					{
782						preview.find ('input[type=text]').focus();
783						return false;
784					}
785
786					preview.find ('button,input,textarea').attr ('disabled','disabled');
787
788					$.post (_this.helper.url({task:'media.update'}), data, function(d){
789						preview.find ('button,input,textarea').removeAttr ('disabled');
790						if (d.status==200)
791						{
792							preview.find('._caption').text( data.name );
793							preview.find('._desc').html( data.description.replace ("\n","<br>") );
794
795							preview.addClass ('_rlt_completed')
796								.removeClass ('_rlt_editing');
797
798							preview.find ('._form_edit ._form_error').hide ();
799						} else {
800							preview.find ('._form_edit ._form_error')
801									.show()
802									.text (d.error);
803						}
804					},'json');
805				})
806				.on('click', '._cancel_edit', function(e){
807					e.preventDefault();
808					preview.addClass('_rlt_completed')
809							.removeClass('_rlt_editing');
810				});
811
812				if ( !form.find('._media_box').length )
813				{
814					form.find ('._controller').before ('<div class="_media_box"></div>');
815				}
816
817				preview.appendTo (form.find ('._media_box'));
818
819				return preview;
820			},
821			html_giphy=function(giphyId){
822				var regexGiphy=/^([A-z0-9]+),([1-9][0-9]*),([1-9][0-9]*)$/;
823				if(!regexGiphy.test(giphyId)) return;
824
825				var attrs=giphyId.match(regexGiphy);
826
827				form.find('.jcm-sticker-preview').off();
828				form.find('.jcm-sticker-preview').remove();
829				form.find('input[name=giphy_id]').remove();
830
831				var gp='<div class="jcm-sticker-preview">';
832						gp+='<div class="giphy-item">';
833							gp+= '<div style="width:100%;height:0;padding-bottom:'+parseInt(attrs[3]*100/attrs[2])+'%;position:relative;"><iframe src="https://giphy.com/embed/'+attrs[1]+'" width="100%" height="100%" style="position:absolute" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div>';
834							gp+='<div class="gif-overlay"></div>';
835						gp+='</div>';
836						gp+= '<input type="hidden" name="giphy_id" value="'+giphyId+'" />';
837						gp+= '<div class="clearfix"></div>';
838						gp+= '<a href="#" class="_remove jcm-tooltip" title="'+_this.lang.get('remove')+'"><i class="fas fa-times" style="font-size:20px;
838color:#777"></i></a>';
839					gp+= '</div>';
840
841				// convert to DOM
842				gp = $(gp);
843				gp.on('click', '._remove', function(e){
844					e.preventDefault();
845					gp.off();
846					gp.remove();
847				});
848				
849				form.find('.jcm-input-cm').after(gp);
850			},
851			mapData = {
852				name : '',
853				icon : '',
854				address : '',
855				lat : null,
856				lng : null
857			};
858
859		// first step
860		if (typeof cdata=='object')
861		{
862			// sticker
863			if ( cdata.hasOwnProperty('sticker') )
864			{
865				html_sticker (cdata.sticker.id, cdata.sticker.url);
866			}
867
868			// sticker
869			if(cdata.hasOwnProperty('giphy_id')) html_giphy(cdata.giphy_id);
870			
871			// map
872			if ( cdata.params!=null && cdata.params.hasOwnProperty('map') && !/^\s*$/.test(cdata.params.map.address) )
873			{
874				mapData = cdata.params.map;
875
876				// update map status
877				form.find('.jcm-map-status,.jcm-btn-geo').addClass ('active');
878				if (mapData.hasOwnProperty('name'))
879				{
880					form.find('.jcm-btn-geo-status').html ('<b>'+mapData.name+'</b> ('+mapData.address+')');
881				} else {
882					form.find('.jcm-btn-geo-status').text (mapData.address);
883				}
884			}
885
886			// media
887			if ( cdata.media!=null && cdata.media.length)
888			{
889				$.each (cdata.media, function(k,file){
890					html_media (file, '_rlt_completed');
891				});
892			}
893
894			// focus to main form
895			if(typeof openform=='undefined' || openform==true)
896			{
897				window.setTimeout (function(){
898					form.find('.jcm-textarea').focus();
899				}, 200);
900			}
901
902			form.on('click','.jcm-btn-cancel',function(){
903				if(form.find('.jcm-btn-emoticon').hasClass('active')) form.find('.jcm-btn-emoticon').trigger('click');
904
905				var bodyCm = _this.box.find('#comment-'+cdata.id+' > .jcm-post-content');
906					bodyCm.children('.jcm-comment-edit').remove();
907					bodyCm.children('.jcm-flex-content').show();
908
909				$('#comment-'+cdata.id).removeClass('editing');
910			});
911		}
912
913		if(!settings.member && (typeof cdata!='object' || (typeof cdata=='object' && !cdata.hasOwnProperty('guest_name'))))
914		{
915			var guestName=_this.helper.cookie.get('jcmGuestName'),
916					guestEmail=_this.helper.cookie.get('jcmGuestEmail');
917
918			if(guestName!=null) form.find('#jcm-input-name-field').val(guestName);
919			if(guestEmail!=null) form.find('#jcm-input-email-field').val(guestEmail);
920		}
921
922		// upload file
923		let mdialog=null;
924
925		form.on('click', '.jcm-btn-upload', function(e) {
926			e.preventDefault();
927			mdialog = new _this.dialog({
928				caption : _this.lang.get('notice'),
929				content : _this.lang.get('media_msg')+'<button class="jup">'+_this.lang.get('select_files')+'</button><div class="or_text">
929'+_this.lang.get('or')+'</div><div class="dropHere">'+_this.lang.get('drag_drop')+'</div>',
930				loadfn: function(dialog){
931					let handleFileUpload=function(files, callback)
932					{
933						let _elbusy = false;
934						if(!files) return false;
935
936						let numfile = form.find('._media_box').find('._rlt_completed, ._rlt_editing, ._rlt_process').length;
937
938						if(settings.maxfilenum>0 && (numfile+files.length)>settings.maxfilenum)
939						{
940							alert(_this.lang.get('maxfilenum_alert'));
941							return;
942						}
943
944						$.each(files, function(k, file){
945							var data = new FormData(),
946								filePreview = html_media ({
947									name : file.name,
948									description : '',
949									fileSize : file.size
950								});
951
952							if(typeof FormData=='undefined')
953							{
954								// not support HTML 5
955								alert(_this.lang.get('upgrade_client_browser'));
956							} else {
957								data.append('file', file);
958
959								let _elTm = window.setInterval(function(){
960									if(_elbusy) return;
961									_elbusy = true;
962									clearInterval(_elTm);
963
964									var xhr = $.ajax({
965										url: _this.helper.url ({task:'media.upload'}),
966										data: data,
967										processData: false,
968										contentType: false,
969										dataType: 'json',
970										xhr: function() {
971											var xhrobj = $.ajaxSettings.xhr();
972											if (xhrobj.upload) {
973										        //obj.addClass('loading');
974										        xhrobj.upload.addEventListener('progress', function(event) {
975										            var percent = 0;
976										            var position = event.loaded || event.position;
977										            var total = event.total;
978										            if (event.lengthComputable) {
979										                percent = Math.ceil(position / total * 100);
980										            }
981										            //Set progress
982										            filePreview.find('._process_bar').css('width',percent+'%');
983										            filePreview.find('._process_result').text(percent);
984										        }, false);
985										    }
986											return xhrobj;
987										},
988										type: 'POST',
989										success: function(d){
990											_elbusy = false;
991
992											//obj.removeClass('loading');
993											if(d.status==200) {
994												filePreview.removeClass('_rlt_process').addClass ('_rlt_completed');
995												filePreview.find ('._media_id').val (d.id);
996											} else {
997												filePreview.removeClass('_rlt_process').addClass ('_rlt_error');
998												filePreview.find ('._error').text (d.error);
999											}
1000										}
1001									});
1002
1003									filePreview.on('click','._cancel', function(e){
1004										e.preventDefault();
1005										if(typeof xhr!='undefined'){
1006											xhr.abort();
1007											_elbusy = false;
1008										}
1009										filePreview.fadeOut (function(){
1010											$(this).remove ();
1011										});
1012									});
1013								}, 100);
1014							}
1015						});
1016					};
1017
1018					let checkValidFile=function(){
1019						let numfile = form.find('._media_box').find('._rlt_completed, ._rlt_editing, ._rlt_process').length;
1020						if(typeof mdialog!=null)
1021							mdialog.off();
1022
1023						if(settings.maxfilenum>0 && numfile>=settings.maxfilenum)
1024						{
1025							alert(_this.lang.get('maxfilenum_alert'));
1026							return false;
1027						}
1028
1029						return true;
1030					};
1031
1032					// drag & drop
1033					dialog.el.find('.dropHere')
1034					.on('dragenter', function(e){
1035						e.stopPropagation();
1036						e.preventDefault();
1037						$(this).addClass('active');
1038					})
1039					.on('dragover', function(e){
1040						e.stopPropagation();
1041						e.preventDefault();
1042					})
1043					.on('drop', function(e){
1044						$(this).removeClass('active');
1045						e.preventDefault();
1046
1047						if(!checkValidFile()) return;
1048						// handle files
1049						// var files = e.originalEvent.dataTransfer.files;
1050						handleFileUpload(e.originalEvent.dataTransfer.files);
1051					});
1052
1053					$(document).on('dragenter', function(e){
1054						e.stopPropagation();
1055						e.preventDefault();
1056					})
1057					.on('dragover', function(e){
1058						e.stopPropagation();
1059						e.preventDefault();
1060						dialog.el.find('.dropHere').removeClass('active');
1061					})
1062					.on('drop', function(e){
1063						e.stopPropagation();
1064						e.preventDefault();
1065					});
1066
1067					dialog.el.find('.jcm-dialog').addClass('uploadFile');
1068					dialog.el.find('.jup').click(function(e){
1069						e.preventDefault();
1070						let _el = $('<input type="file" multiple style="width:1px;height:1px;overflow:hidden" />');
1071						let _elbusy = false;
1072
1073						_el.appendTo('body');
1074
1075						if(!checkValidFile()) return;
1076
1077						_el.change(function(evt){
1078							handleFileUpload(evt.target.files);
1079						});
1080						_el.trigger('click');
1081					});
1082				},
1083				submitLabel : false,
1084				cancelLabel: _this.lang.get('ok')
1085			});
1086		});
1087
1088		// text format
1089		if(_this.browser.contenteditable)
1090		{
1091			var $tools=form.find('.jcm-text-fm'),
1092				editorFocus=false,
1093				getSelectedNode=function(){
1094				if (document.selection)
1095			        return document.selection.createRange().parentElement();
1096			    else
1097			    {
1098			        var selection = window.getSelection();
1099			        if(selection.rangeCount>0)
1100			            return selection.getRangeAt(0).startContainer.parentNode;
1101			    }
1102			};
1103
1104			form.find('.jcm-textarea').on('focus blur', function(e){
1105				editorFocus=e.type=='focus';
1106			});
1107
1108			$tools.removeClass('hide');
1109			window.setInterval(function(){
1110				if(!editorFocus) return;
1111
1112				var $el=$(getSelectedNode());
1113				if($el.is('a')){
1114					$tools.find('[data-tag=unlink]').show();
1115					$tools.find('[data-tag=createLink]')
1116						.removeAttr('disabled')
1117						.addClass('active');
1118				} else {
1119					$tools.find('[data-tag=unlink]').hide();
1120					$tools.find('[data-tag=createLink]').removeClass('active');
1121
1122					if(window.getSelection().toString()!=''){
1123						$tools.find('[data-tag=createLink],[data-tag=code],[data-tag=quote]')
1124							.removeAttr('disabled');
1125					} else {
1126						$tools.find('[data-tag=createLink],[data-tag=code],[data-tag=quote]')
1127							.attr('disabled', 'disabled');
1128					}
1129				}
1130
1131				// status
1132				var listCmd=['bold','italic','underline','strikeThrough'];
1133				$.each(listCmd, function(k,cmd){
1134					if(document.queryCommandState(cmd)){
1135						$tools.find('[data-tag='+cmd+']').addClass('active');
1136					} else {
1137						$tools.find('[data-tag='+cmd+']').removeClass('active');
1138					}
1139				});
1140			}, 500);
1141
1142			$tools.on('click', '[data-tag]', function(e){
1143				e.preventDefault();
1144				var tag=$(this).attr('data-tag');
1145				switch(tag)
1146				{
1147					case 'createLink':
1148						var $el=$(getSelectedNode()),
1149							oldlink='';
1150
1151						if($el.is('a'))
1152						{
1153							oldlink=$el.attr('href');
1154
1155							// select this element
1156							var range = document.createRange();
1157						    range.selectNodeContents($el[0]);
1158						    var sel = window.getSelection();
1159						    sel.removeAllRanges();
1160						    sel.addRange(range);
1161						}
1162
1163						var link = prompt(_this.lang.get('insert_your_link'), oldlink);
1164						if(link!=null){
1165							if(!/(https?:\/\/[^\s]+)/g.test(link)){
1166								alert(_this.lang.get('link_format_incorrect'));
1167								return;
1168							}
1169							document.execCommand("CreateLink", false, link);
1170						}
1171						break;
1172
1173					case 'unlink':
1174						var $el=$(getSelectedNode());
1175						if(!$el.is('a')) return;
1176
1177						$el.contents().unwrap('a');
1178						break;
1179
1180					case 'quote':
1181					case 'code':
1182						document.execCommand("insertHTML", false, '<div data-tag="'+tag+'">'+document.getSelection().toString().replace(/&/g, "&amp;")
1183						.replace(/</g, "&lt;")
1184						.replace(/>/g, "&gt;")
1185						.replace(/"/g, "&quot;")
1186						.replace(/'/g, "&#039;")
1187						.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')+'</div><br>');
1188						break;
1189
1190					default:
1191						document.execCommand(tag, false, null);
1192						if(window.getSelection().toString()=='')
1193							form.find('.jcm-textarea').focus();
1194						break;
1195				}
1196			});
1197		}
1198
1199
1200		// add sticker
1201		var dialogSticker = null;
1202		form.on('click', '.jcm-btn-sticker', function(e){
1203			if(dialogSticker!=null)
1204				return false;
1205			e.preventDefault();
1206
1207			dialogSticker = new _this.dialog ({
1208				caption : _this.lang.get('sticker'),
1209				content : _this.lang.get('please_wait'),
1210				submitLabel : false,
1211				cancelfn : function(dialog)
1212				{
1213					dialogSticker = null;
1214				},
1215				loadfn : function(dialog)
1216				{
1217					dialog.el.find('.jcm-dialog').addClass('sticker');
1218					new _this.sticker({
1219						parent : dialog.el.find('.jcm-dg-content'),
1220						selected : function (id, url, cb) {
1221							var comment = form.find('.jcm-textarea').is('textarea') ? form.find('.jcm-textarea').val() : form.find('.jcm-textarea').text();
1222							
1223							if(settings.sticker_autopost==1 && typeof cb=='undefined')
1224							{
1225								if(/^\s*$/.test(comment) && !form.find ('.forGuest').length)
1226								{
1227									form.find('form').append('<input type="hidden" name="sticker_id" value="'+id+'" />');
1228									form.find('form').trigger('submit');
1229								} else {
1230									html_sticker(id, url);
1231								}
1232							} else {
1233								$imger = html_sticker(id, url);
1234								if(typeof cb=='function') cb($imger);
1235							}
1236							
1237							dialog.off();
1238							dialogSticker=null;
1239						}
1240					});
1241				}
1242			});
1243		});
1244
1245		// attach location
1246		var dialogMap = null;
1247		form.on('click', '.jcm-btn-geo,.jcm-btn-geo-status', function(e){
1248			if(dialogMap!=null)
1249				return false;
1250
1251			e.preventDefault();
1252
1253			var mapDataTmp = mapData;
1254
1255			dialogMap = new _this.dialog ({
1256				caption : _this.lang.get('embed_location'),
1257				content : '<div class="mapContent">'+_this.lang.get('please_wait')+'</div>',
1258				submitLabel : _this.lang.get('add'),
1259				submitfn : function (dialog)
1260				{
1261					mapData = mapDataTmp;
1262					dialog.off ();
1263					dialogMap = null;
1264					if ( !form.find('input[name=map_lat]').length )
1265					{
1266						var html = '<input type="hidden" name="map_lat" value= ""/>';
1267							html+= '<input type="hidden" name="map_lng" value= ""/>';
1268							html+= '<input type="hidden" name="map_address" value= ""/>';
1269							html+= '<input type="hidden" name="map_name" value= ""/>';
1270							html+= '<input type="hidden" name="map_icon" value= ""/>';
1271						form.find ('form').append (html);
1272					}
1273
1274					form.find ('input[name=map_lat]').val (mapData.lat);
1275					form.find ('input[name=map_lng]').val (mapData.lng);
1276					form.find ('input[name=map_address]').val (mapData.address);
1277					form.find ('input[name=map_name]').val (mapData.name);
1278					form.find ('input[name=map_icon]').val (mapData.icon);
1279
1280					// update map status
1281					form.find('.jcm-map-status,.jcm-btn-geo').addClass ('active');
1282
1283					if (mapData.hasOwnProperty('name'))
1284					{
1285						form.find('.jcm-btn-geo-status').html ('<b>'+mapData.name+'</b> ('+mapData.address+')');
1286					} else {
1287						form.find('.jcm-btn-geo-status').text (mapData.address);
1288					}
1289					
1290				},
1291				cancelfn : function (dialog)
1292				{
1293					dialogMap = null;
1294				},
1295				loadfn : function (dialog)
1296				{
1297					dialog.el.find('.jcm-dialog').addClass('map');
1298					window.setTimeout (function()
1299					{
1300						var map = new google.maps.Map(dialog.el.find(".mapContent")[0],
1301							{
1302								center: {lat: -33.8688, lng: 151.2195},
1303								zoom: 13
1304					        }),
1305							html = '<div class="pac-box"><input type="text" class="pac-input" /></div>';
1306							html+= '<div class="infowindow-content">';
1307							html+= '<img src="" alt="" width="16" height="16" class="_icon">';
1308							html+= '<span class="_name"  class="title"></span><br>';
1309							html+= '<span class="_address"></span></div>';
1310
1311						dialog.el.find('.jcm-dg-content').prepend(html);
1312
1313				        var input = dialog.el.find('input.pac-input'),
1314				        	pac_box = dialog.el.find('.pac-box')[0];
1315
1316				        map.controls[google.maps.ControlPosition.TOP_RIGHT].push(pac_box);
1317
1318				        var autocomplete = new google.maps.places.Autocomplete(input[0]);
1319				        autocomplete.bindTo('bounds', map);
1320
1321				        var infowindow = new google.maps.InfoWindow(),
1322				        	infowindowContent = dialog.el.find('.infowindow-content');
1323				        	infowindow.setContent(infowindowContent[0]);
1324
1325				        var marker = new google.maps.Marker({
1326							map: map,
1327							anchorPoint: new google.maps.Point(0, -29)
1328				        });
1329
1330				        // Bind map if have values
1331						if (mapData.lat!=null)
1332						{
1333							var marker_loc  = new google.maps.LatLng(mapData.lat,
1334								mapData.lng);
1335
1336							marker.setPosition(marker_loc);
1337							marker.setVisible(true);
1338							
1339							input.val (mapData.address);
1340
1341							if (mapData.hasOwnProperty('name'))
1342							{
1343								infowindowContent.find('._name').text(mapData.name);
1344							}
1345							
1346							infowindowContent.find('._address').text(mapData.address);
1347							infowindowContent.find('._icon').attr("src", mapData.icon);
1348							infowindow.open(map, marker);
1349						}
1350
1351				        autocomplete.addListener('place_changed', function() {
1352							infowindow.close();
1353							marker.setVisible(false);
1354							var place = autocomplete.getPlace();
1355							if (!place.geometry)
1356							{
1357								window.alert(_this.lang.get("map_not_found") + ": '" + place.name + "'");
1358								return;
1359							}
1360
1361							// If the place has a geometry, then present it on a map.
1362							if (place.geometry.viewport)
1363							{
1364								map.fitBounds(place.geometry.viewport);
1365							} else {
1366								map.setCenter(place.geometry.location);
1367								map.setZoom(17);  // Why 17? Because it looks good.
1368							}
1369
1370							marker.setPosition(place.geometry.location);
1371							marker.setVisible(true);
1372
1373							var address = '';
1374							if (place.address_components)
1375							{
1376								address = [
1377								(place.address_components[0] && place.address_components[0].short_name || ''),
1378								(place.address_components[1] && place.address_components[1].short_name || ''),
1379								(place.address_components[2] && place.address_components[2].short_name || '')
1380								].join(' ');
1381							}
1382
1383							infowindowContent.find('._icon').attr("src", place.icon);
1384							infowindowContent.find('._name').text(place.name);
1385							infowindowContent.find('._address').text(address);
1386							infowindow.open(map, marker);
1387							
1388							mapDataTmp.lat = marker.getPosition().lat();
1389							mapDataTmp.lng = marker.getPosition().lng();
1390							mapDataTmp.name = place.name;
1391							mapDataTmp.address = address;
1392							mapDataTmp.icon = place.icon;
1393						});
1394					}, 300);
1395				}
1396			});
1397		})
1398		.on('click', '.jcm-empty-geo', function(e){
1399			e.preventDefault();
1400			form.find('[name="map_lat"],[name="map_lng"],[name="map_address"]').remove ();
1401			mapData = {
1402				name : '',
1403				icon : '',
1404				address : '',
1405				lat : null,
1406				lng : null
1407			};
1408			form.find('.jcm-map-status,.jcm-btn-geo').removeClass ('active');
1409		});
1410
1411		form.on('click', '.jcm-btn-emoticon', function(e){
1412			e.preventDefault();
1413			_this.emoji.input = form.find('.jcm-textarea');
1414			_this.emoji.toggle($(this));
1415		});		
1416
1417		// comment style
1418		form.on('click', '.jcm-btn-style', function(e){
1419			e.preventDefault();
1420			var sl=null,
1421				slId=parseInt(form.find('[name=style_id]').val());
1422				slId=(isNaN(slId)||slId<1)?0:slId;
1423
1424			_this.dialog({
1425				caption : _this.lang.get('cm_style'),
1426				content : _this.lang.get('please_wait'),
1427				submitLabel : _this.lang.get('apply'),
1428				loadfn : function(dialog)
1429				{
1430					var slCallback=function(){
1431						var ls=$('<div class="jcm-styles"></div>');
1432						$.each(_this.styles, function(k,v)
1433						{
1434							var item='<div class="jcm-style-item'+(v.id==slId?' active':'')+'">'+v.caption+'</div>';
1435								item=$(item);
1436
1437							if(v.id==slId) sl=v;
1438
1439							item.attr('style', v.css);
1440							item.appendTo(ls);
1441
1442							item.click(function(){
1443								if(item.hasClass('active'))
1444								{
1445									item.removeClass('active');
1446									slId=0; sl=null;
1447									return;
1448								}
1449
1450								item.addClass('active');
1451								item.siblings().removeClass('active');
1452								slId=v.id;
1453								sl=v;
1454							});
1455						});
1456
1457						dialog.el.find('.jcm-dg-content').empty().append(ls);
1458					};
1459
1460					if(_this.styles==null){
1461						$.post(_this.helper.url({task:'others.styles'}), function(d){
1462							_this.styles = d;
1463							if(d==null)
1464							{
1465								dialog.el.find('.jcm-dg-content').html('<span>'+_this.lang.get('no_style')+'</span>');
1466								return;
1467							}
1468
1469							slCallback();
1470						}, 'json');
1471					} else {
1472						slCallback();
1473					}
1474				},
1475				submitfn : function(dialog)
1476				{
1477					if(form.find('[name=style_id]').length)
1478					{
1479						form.find('[name=style_id]').val(slId);
1480					} else {
1481						form.find('.jcm_form_input').append('<input type="hidden" name="style_id" value="'+slId+'">');
1482					}
1483
1484					if(sl)
1485					{
1486						form.find('.jcm-textarea').attr('style',sl.css);
1487						form.find('.jcm-input-cm').addClass('_style');
1488						if(sl.maxlength>0) settings.cm_max_length = sl.maxlength*1;
1489					} else {
1490						form.find('.jcm-textarea').removeAttr('style');
1491						form.find('.jcm-input-cm').removeClass('_style');
1492						settings.cm_max_length = 0;
1493					}
1494
1495					form.find('.jcm-textarea').focus();
1496					dialog.off();
1497				}
1498			});
1499		});
1500
1501		// giphy
1502		form.on('click', '.jcm-btn-gif', function (e){
1503			e.preventDefault();
1504			if(settings.giphy=='') return;
1505
1506			var gh='<div>';
1507					gh+='<div class="gif-input">';
1508						gh+='<input type="text" placeholder="'+_this.lang.get('find_gif_image')+'">'
1509					gh+='</div>';
1510
1511					gh+='<div class="gif-output"></div>';
1512				gh+='</div>';
1513
1514			var dialogGif = new _this.dialog ({
1515				caption : _this.lang.get('giphy'),
1516				content : gh,
1517				submitLabel : false,
1518				loadfn : function (dialog)
1519				{
1520					dialog.el.find('.jcm-dialog').addClass('giphy');
1521
1522					let giphyId=null,
1523						giphyFinder=null;
1524					dialog.el.find('input[type="text"]').keypress(function(){
1525						if(giphyFinder!=null) clearTimeout(giphyFinder);
1526
1527						giphyFinder=setTimeout(function(){
1528							var giphyQuery=$.trim(dialog.el.find('input[type="text"]').val());
1529							if(giphyQuery.length<3) return;
1530
1531							var giphyOutput=dialog.el.find('.gif-output');
1532								giphyOutput.empty().append(_this.lang.get('please_wait'));
1533
1534
1535							$.get('https://api.giphy.com/v1/gifs/search?api_key='+settings.giphy+'&limit=15&q='+giphyQuery, function(d){
1536
1537								giphyOutput.empty();
1538
1539								if(!d.hasOwnProperty('data')){
1540									giphyOutput.append('Error: '+d.message);
1541									return;
1542								}
1543
1544								if(!d.data.length)
1545								{
1546									giphyOutput.append(_this.lang.get('gif_empty_result'));
1547									return;
1548								}
1549
1550								var ghOutput='';
1551								$.each(d.data, function(k1,v1){
1552									ghOutput+='<div class="giphy-item" data-id="'+v1.id+','+v1.images.original.width+','+v1.images.original.height+'">';
1553										ghOutput+='<div style="width:100%;height:0;padding-bottom:'+parseInt(v1.images.original.height*100/v1.images.original.width)+'%;position:relative;"><iframe src="https://giphy.com/embed/'+v1.id+'" width="100%" height="100%" style="position:absolute" frameBorder="0" class="giphy-embed" allowFullScreen></iframe></div>';
1554										ghOutput+='<div class="gif-overlay"></div>';
1555									ghOutput+='</div>';
1556								});
1557
1558								giphyOutput.append(ghOutput);
1559							},'json');
1560						}, 500);
1561					});
1562
1563					dialog.el.on('click', '.giphy-item', function(){
1564						html_giphy($(this).attr('data-id'));
1565						dialog.off();
1566					});
1567
1568					dialog.el.find('input[type="text"]').focus();
1569				}
1570			});
1571		});
1572
1573		form.find('._controller').attr('data-tool', form.find('._controller .
1573jcm-btn-open').length);
1574
1575		// focus comment textbox
1576		form.on('focus', '.jcm-textarea', function(){
1577			form.addClass('active');
1578			form.find('.jcm-text-placeholder').removeClass('active');
1579			_this.box.trigger('emoji');
1580		})
1581		.on('blur', '.jcm-textarea', function(){
1582			if($(this).html()=='')
1583				form.find('.jcm-text-placeholder').addClass('active');
1584		});
1585
1586		if(settings.cm_max_length>0)
1587		{
1588			var maxSb = form.find('.symbol-count').attr('data-max')*1;
1589			form.on('keydown paste focus', '.jcm-textarea', function(e){
1590				var _el = $(this);
1591				window.setTimeout(function(){
1592					var lengthSb = 0;
1593					if(_el.is('textarea')){
1594						lengthSb = _el.val().length;
1595					} else {
1596						var $cc = _el.clone();
1597							$cc.find('img.emoji').each(function(){
1598								$(this).replaceWith('-');
1599							});
1600
1601						lengthSb = $cc.text().length;
1602					}
1603
1604					if(lengthSb>maxSb)
1605					{
1606						form.find('.symbol-count').addClass ('error');
1607					} else {
1608						form.find('.symbol-count').removeClass ('error');
1609					}
1610					form.find('.symbol-count').text (maxSb - lengthSb);
1611				}, e.type=='focusin'?300:100);
1612			});
1613		}
1614
1615		// convert to plain-text
1616		if(_this.browser.contenteditable)
1617		{
1618			!function(a){a.fn.caret=function(a){var b=this[0],c=b&&"true"===b.contentEditable;if(0!=arguments.length){if(b){if(a==-1&&(a=this[c?"text":"val"]().length),window.getSelection)c?(b.focus(),window.getSelection().collapse(b.firstChild,a)):b.setSelectionRange(a,a);else if(document.body.createTextRange)if(c){var f=document.body.createTextRange();f.moveToElementText(b),f.moveStart("character",a),f.collapse(!0),f.select()}else{var f=b.createTextRange();f.move("character",a),f.select()}c||b.focus()}return this}if(b){if(window.getSelection){if(c){b.focus();var d=window.getSelection().getRangeAt(0),e=d.cloneRange();return e.selectNodeContents(b),e.setEnd(d.endContainer,d.endOffset),e.toString().length}return b.selectionStart}if(document.selection){if(b.focus(),c){var d=document.selection.createRange(),e=document.body.createTextRange();return e.moveToElementText(b),e.setEndPoint("EndToEnd",d),e.text.length}var a=0,f=b.createTextRange(),e=document.selection.createRange().duplicate(),g=e.getBookmark();for(f.moveToBookmark(g);0!==f.moveStart("character",-1);)a++;return a}if(b.selectionStart)return b.selectionStart}}}(jQuery);
1619
1620			var __pasteHtml = function (html) {
1621				    var sel, range;
1622				    if (window.getSelection) {
1623				        // IE9 and non-IE
1624				        sel = window.getSelection();
1625				        if (sel.getRangeAt && sel.rangeCount) {
1626				            range = sel.getRangeAt(0);
1627				            range.deleteContents();
1628
1629				            // Range.createContextualFragment() would be useful here but is
1630				            // only relatively recently standardized and is not supported in
1631				            // some browsers (IE9, for one)
1632				            var el = document.createElement("div");
1633				            el.innerHTML = html;
1634				            var frag = document.createDocumentFragment(), node, lastNode;
1635				            while ( (node = el.firstChild) ) {
1636				                lastNode = frag.appendChild(node);
1637				            }
1638				            range.insertNode(frag);
1639
1640				            // Preserve the selection
1641				            if (lastNode) {
1642				                range = range.cloneRange();
1643				                range.setStartAfter(lastNode);
1644				                range.collapse(true);
1645				                sel.removeAllRanges();
1646				                sel.addRange(range);
1647				            }
1648				        }
1649				    } else if (document.selection && document.selection.type != "Control") {
1650				        // IE < 9
1651				        document.selection.createRange().pasteHTML(html);
1652				    }
1653				},
1654				__lastChr = 0;
1655
1656			form.on('paste', '.jcm-textarea', function(e) {
1657				if (typeof window.clipboardData=='undefined')
1658				{
1659					e.stopPropagation();
1660					e.preventDefault();
1661
1662					document.execCommand('insertHTML', false, e.originalEvent.clipboardData.getData('text').replace(/&/g, "&amp;")
1663						.replace(/</g, "&lt;")
1664						.replace(/>/g, "&gt;")
1665						.replace(/"/g, "&quot;")
1666						.replace(/'/g, "&#039;")
1667						.replace(/(?:\r\n|\r|\n)/g, '<br>')
1668						.replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;'));
1669				} else {
1670					// ie disable access to clipboard
1671					var _content  = '',
1672						_input 	  = $(this),
1673						_textarea = document.createElement('textarea'),
1674						_caretPos = _input.caret();
1675
1676					$(_textarea).attr("style", "width:1px;height:1px;overflow:hidden;opacity:0");
1677					$(_textarea).appendTo(form);
1678
1679					$(_textarea).focus();
1680
1681					window.setTimeout(function(){
1682						_content = $(_textarea).val();
1683						_content = _content.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + '<br>' + '$2');
1684						$(_textarea).remove();
1685
1686						_input.focus();
1687						if (_caretPos > 0)
1688						{
1689							_input.caret(_caretPos);
1690						}
1691						
1692						__pasteHtml(_content);
1693					},100);
1694				}
1695			});
1696		}
1697
1698
1699		// mention
1700		if(typeof settings.peoples=='object' && settings.peoples.length && _this.browser.contenteditable==true)
1701		{
1702			var peoplesfm = [];
1703
1704			$.each (settings.peoples, function(k,v){
1705				v.value = v.id;
1706				v.key = v.name + ' ' +v.username;
1707				peoplesfm.push (v);
1708			});
1709
1710			var tribute = new Tribute({
1711		        menuContainer: document.getElementById('content'),
1712		        values: peoplesfm,
1713		        selectTemplate: function (item) {
1714		          if (this.range.isContentEditable(this.current.element)) {
1715		            return '<span class="jcm-mention" contenteditable="false" data-id="'+item.original.id+'">
1715'+(settings.author_name==1?item.original.name:item.original.username)+'</span>';
1716		          }
1717
1718		          return '@' + (settings.author_name==1?item.original.name:item.original.username);
1719		        },
1720		        noMatchTemplate: function (tribute) {
1721		          return '<li>'+_this.lang.get('no_match')+'</li>';
1722		        },
1723		        menuItemTemplate: function (item) {
1724		        	var _fm = '<img src="'+item.original.thumb+'" alt=""/>';
1725		        		if (settings.author_name==1)
1726		        		{
1727		        			_fm+= '<span class="_name">'+item.original.name+'</span>';
1728							_fm+= '<span class="_uname">@'+item.original.username+'</span>';
1729		        		} else {
1730		        			_fm+= '<span class="_name">@'+item.original.username+'</span>';
1731							_fm+= '<span class="_uname">'+item.original.name+'</span>';
1732		        		}
1733						
1734					return _fm;
1735				},
1736		    });
1737
1738		    tribute.attach(form.find('.jcm-textarea')[0] );
1739		}
1740
1741		// format checkbox
1742		form.find('input.__fm').each(function(){
1743			var _el = $(this),
1744				_cOn = 'fas fa-check-square',
1745				_cOff = 'far fa-square',
1746				_nel = $('<i class="'+(_el.is(':checked')?_cOn:_cOff)+'"></i>');
1747
1748				_el.change(function(){
1749					if(_el.is(':checked')) {
1750						_nel.addClass(_cOn).removeClass(_cOff);
1751					} else {
1752						_nel.addClass(_cOff).removeClass(_cOn);
1753					}
1754				});
1755
1756				_nel.insertAfter(_el);
1757				_el.hide();
1758		});
1759
1760		// submit
1761		form.on('submit', '.jcm_form_input', function(e){
1762			e.preventDefault();
1763			var _form = $(this),
1764				data = _form.serializeArray();
1765
1766			if(!_form.find('textarea.jcm-textarea').length)
1767			{
1768				var CmClone = _form.find('.jcm-textarea').clone();
1769				CmClone.find('img.emoji').each(function(){
1770					$(this).replaceWith($(this).attr('alt'));
1771				});
1772
1773				data.push({name:'comment', value:CmClone.html()});
1774				data.push({name:'plaintext', value:0});
1775			}
1776
1777			data.push({name:'key', value:_this.config.key});
1778
1779			// name & email of guest
1780			if(form.find('.forGuest').length)
1781			{
1782				var author_name = form.find ('#jcm-input-name-field').val (),
1783					author_email = form.find ('#jcm-input-email-field').val ();
1784
1785				data.push({name:'guest_name', value:author_name});
1786				data.push({name:'guest_email', value:author_email});
1787
1788				_this.helper.cookie.set('jcmGuestName', author_name, 5);
1789				_this.helper.cookie.set('jcmGuestEmail', author_email, 5);
1790			}
1791
1792			var formfn = {
1793					countEvent 	: 0,
1794					passEvent	: 0,
1795					el 			: form,
1796					data 		: data
1797				};
1798
1799			formfn.submit = function(callback)
1800			{
1801				if(formfn.countEvent!=formfn.passEvent) return false;
1802
1803				if(form.find('.jcm-btn-emoticon.active').length)
1804				{
1805					form.find('.jcm-btn-emoticon').trigger('click');
1806				}
1807
1808				form.find('.jcm-protect-layer').addClass('active');
1809
1810				$.post(_form.attr('action') , data, function(response){
1811
1812					form.find('.jcm-protect-layer').removeClass('active');
1813
1814					if(typeof callback=='function')
1815					{
1816						callback(response);
1817					}
1818
1819					if(typeof response!='object' || response.status==400)
1820					{
1821						// put error here
1822						form.find('.jcm_form_error').addClass ('active')
1823							.text(response.error);
1824						/*$("html, body").animate({scrollTop:form.find('.jcm_form_error').offset().top-50},500);*/
1825						return false;
1826					}
1827
1828					var parent_id = form.find('[name=parent_id]').length==1 ? form.find('[name=parent_id]:eq(0)').val()*1 : 0,
1829						cm_id = form.find('[name=id]').length==1 ? form.find ('[name=id]:eq(0)').val()*1 : 0;
1830
1831					if(cm_id>0)
1832					{
1833						// comment modified.
1834						$.get(_this.helper.url({task:'items.loadCm',id:cm_id}), function(d){
1835							if(typeof d!='object' || d.status==400)
1836							{
1837								// put error here
1838								return;
1839							}
1840
1841							var cmBlock = _this.box.find('#comment-'+cm_id+'>.jcm-post-content>.jcm-flex-content');
1842								cmBlock.empty().append(d.html);
1843
1844							form.closest('.jcm-block')
1845								.children('.jcm-post-content')
1846								.find('jcm-post-footer .jcm-edit')
1847								.removeClass('active');
1848							form.parent().remove();
1849							cmBlock.show();
1850
1851							$('#comment-'+cm_id).removeClass('editing');
1852						},'json');
1853
1854						return;
1855					}
1856
1857					// suggest subscribe
1858					if(form.find('input[name=__sub]:checked').length)
1859					{
1860						if (typeof response.sub=='object' && response.sub.status==200)
1861						{
1862							if (response.sub.hasOwnProperty('hash'))
1863							{
1864								_this.box.find('.jcm-subscribe').attr('data-hash',response.sub.hash);
1865							}
1866
1867							if (response.sub.hasOwnProperty('verifyRequire') && response.sub.verifyRequire==1)
1868							{
1869								window.setTimeout(function(){
1870									var dialog = new _this.dialog ({
1871										caption 	: _this.lang.get('subscribe'),
1872										content 	: _this.lang.get('subscribe_verify', response.sub.email),
1873										submitLabel : false,
1874										cancelLabel : _this.lang.get('ok')
1875									});
1876								},1000);
1877							}
1878
1879							_this.box.find('.jcm-subscribe')
1880								.addClass('_on')
1881								.removeClass('_off');
1882
1883							_this.tpl.form.find('.jcm-suggest-follow').remove();
1884						}
1885					}
1886
1887					var _config = {
1888						timestamp : 0,
1889						sort : 'desc',
1890						page_comment: 1,
1891						timestamp_offset:_this.timestamp.hasOwnProperty(parent_id) ? _this.timestamp[parent_id] : _this.config.timestamp
1892					}
1893
1894					if(parent_id>0)
1895					{
1896						_config.parent_id = parent_id;
1897
1898						if(settings.child_style=='1' && form.find('[name=root_id]').length)
1899						{
1900							var rootId = form.find('[name=root_id]').val();
1901							if(/^[1-9][0-9]*$/.test(rootId))
1902							{
1903								parent_id = rootId;
1904								_config.parent_id = rootId;
1905								_config.timestamp_offset = _this.timestamp.hasOwnProperty(rootId)?_this.timestamp[rootId]:_this.config.timestamp;
1906							}
1907						}
1908					}
1909
1910					var showDir = parent_id>0?(settings.sortC=='desc'?'up':'down'):(settings.sort=='desc'?'up':'down');
1911
1912					
1913					_this.reload(_config, function(d){
1914						if(_config.hasOwnProperty('parent_id')){
1915							_this.timestamp[_config.parent_id]=d.timestamp;
1916						} else {
1917							_this.timestamp[parent_id]=d.timestamp;
1918						}
1919						
1920						if(parent_id>0)
1921						{
1922							var replyBox = _this.box.find('#comment-'+parent_id+'>.jcm-post-content');
1923							if(!replyBox.children('.jcm-list-reply').length)
1924							{
1925								replyBox.append('<div class="jcm-list-reply"><ul class="jcm-childs"></ul></div>');
1926							}
1927
1928							if(showDir=='up'){
1929								replyBox.children('.jcm-list-reply').children('.jcm-childs').prepend(d.html);
1930							} else {
1931								replyBox.children('.jcm-list-reply').children('.jcm-childs').append(d.html);
1932							}
1933						
1934							form.parent().prev('ul.inline').find('.jcm-reply').removeClass('active');
1935							form.parent().remove();
1936						} else {
1937							if ( !_this.box.find('.jcm-root').length )
1938							{
1939								_this.box.find('.jcm-empty-cm').fadeOut('fast',function(){
1940									$(this).remove();
1941								});
1942								_this.box.find('#jcm-comments').append('<ul class="jcm-root"></ul>');
1943							}
1944
1945							if(showDir=='up'){
1946								_this.box.find('.jcm-root').prepend(d.html);
1947							} else {
1948								_this.box.find('.jcm-root').append(d.html);
1949							}
1950							
1951
1952							// reset form
1953							let _el=_this.tpl.form.clone();
1954								form.replaceWith(_el);
1955							_this.createFormEvents(_el);
1956
1957							// remove term
1958							if(settings.ruleOnce)
1959								$('input[name=__term]').parents('.jcm-subdiv').remove();
1960						}
1961
1962						// clear cache
1963						_this.tmpCache = {};
1964
1965						// scroll to new comment
1966						var latestId=$(d.html).filter('.jcm-block:eq(0)').attr('id');
1967						
1968						if(!settings.dis_scroll)
1969						{
1970							$('html, body').animate({
1971						        scrollTop: _this.box.find('#'+latestId).offset().top-100
1972						    }, 200, function(){
1973						    	_this.box.find('#'+latestId).addClass('_light');
1974						    });
1975						}
1976					});
1977				}, 'json');
1978			};
1979
1980			var formError = [];
1981			(function()
1982			{
1983				if (form.find ('#jcm-input-name-field').length && /^\s*$/.test(form.find ('#jcm-input-name-field').val()))
1984				{
1985					formError.push (_this.lang.get('fill_your_name'));
1986				}
1987
1988				var regexEmail = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
1989					__elEmail  = form.find('#jcm-input-email-field');
1990				if (__elEmail.length)
1991				{
1992					if((__elEmail.attr('data-require')==1 && !regexEmail.test(__elEmail.val()))
1993						|| (__elEmail.attr('data-require')==0 && !regexEmail.test(__elEmail.val()) && !/^\s*$/.test(__elEmail.val()))	
1994					  )
1995					{
1996						formError.push(_this.lang.get('email_incorrect'));
1997					}
1998				}
1999
2000				// check length of comment
2001				var _el = form.find('.jcm-textarea'),
2002					lengthCm = 0;
2003
2004				if(_el.is('textarea')){
2005					lengthCm = _el.val().length;
2006				} else {
2007					var $cc = _el.clone();
2008						$cc.find('img.emoji').each(function(){
2009							$(this).replaceWith('-');
2010						});
2011
2012					lengthCm = $cc.text().length;
2013				}
2014				
2015				if (settings.cm_min_length>0)
2016				{
2017					if (lengthCm<settings.cm_min_length)
2018					{
2019						formError.push (_this.lang.get('min_comment_length',settings.cm_min_length));
2020					}
2021				} else {
2022					var sticker = form.find('input[name=sticker_id]');
2023					if ((!sticker.length || sticker.val()<1) && lengthCm<1)
2024					{
2025						formError.push (_this.lang.get('comment_empty'));
2026					}
2027				}
2028
2029				if (settings.cm_max_length>0 && lengthCm>settings.cm_max_length)
2030				{
2031					formError.push (_this.lang.get('comment_too_long'));
2032				}
2033
2034				// sub but missing email - for guest only
2035				if(settings.member==0 && form.find('input[name=__sub]:checked').length && (!__elEmail.length||(__elEmail.length && !regexEmail.test(__elEmail.val()))))
2036				{
2037					formError.push (_this.lang.get('subscribe_email_require'));
2038				}
2039
2040				// term
2041				if(form.find('input[name=__term]').length && !form.find('input[name=__term]:checked').length)
2042				{
2043					formError.push(_this.lang.get('term_checkbox_err'));
2044				}
2045			})();
2046
2047			if(formError.length>0)
2048			{
2049				form.find ('.jcm_form_error').addClass ('active')
2050							.html (formError.join("<br/>"));
2051
2052				if(!settings.dis_scroll)
2053				{
2054					$("html, body").animate({scrollTop:form.find('.jcm_form_error').offset().top-50},500);
2055				}
2056				return false;
2057			} else {
2058				form.find ('.jcm_form_error').removeClass ('active');
2059			}
2060
2061			_this.listenEvent('jcm.submit',{$:$, jcm:_this, form:formfn});
2062
2063			if (formfn.countEvent==0)
2064			{
2065				formfn.submit();
2066			}
2067		});
2068
2069		// trigger submit event
2070		form.on('click', '.jcm-btn-submit', function(){
2071			form.find('.jcm_form_input').trigger('submit');
2072		});
2073	};
2074
2075	this.sharefn = function()
2076	{
2077		_this.box.on('click','.jcm-share', function(e){
2078			e.preventDefault();
2079			var _el  = $(this),
2080				id = _el.attr ('data-id'),
2081				comment_preview = _this.box.find('#comment-'+id+' .jcm-post-body:eq(0)').text();
2082
2083			let url = '';
2084
2085			comment_preview = $.trim (comment_preview);
2086
2087			if(settings.linkshare=='query'){
2088				url  = settings.url + (settings.url.indexOf('?')==-1?'?':'&')+'comment_id='+id;
2089			} else {
2090				url  = settings.url+'#comment-'+id;
2091			}
2092
2093			var content = '<input type="text" readonly value="'+url+'" style="margin: 10px auto;background: #fff;" />',
2094				shareTools = [];
2095
2096			content+='<div style="text-align: center; font-weight: bold; margin: -5px 0 5px 0;"><span class="cp-stt" style="display:none">'+_this.lang.get('copied')+'</span></div>';
2097
2098			if (_el.attr('data-fb')==1)
2099			{
2100				shareTools.push('<li><a href="#" class="jcm-share-fb jcm-share-item" data-type="fb"><i class="fab fa-facebook-f"></i></a></li>');
2101			}
2102
2103			if (_el.attr('data-tw')==1)
2104			{
2105				shareTools.push('<li><a href="#" class="jcm-share-tw jcm-share-item" data-type="tw"><i class="fab fa-twitter"></i></a></li>');
2106			}
2107
2108			if (_el.attr('data-gg')==1)
2109			{
2110				shareTools.push('<li><a href="#" class="jcm-share-gg jcm-share-item" data-type="gg"><i class="fab fa-google"></i></a></li>');
2111			}
2112
2113			if (shareTools.length)
2114			{
2115				content+= '<ul class="jcm-inline" style="text-align:center">';
2116					content+= shareTools.join ('');
2117				content+= '</ul>';
2118			}
2119			
2120			new _this.dialog ({
2121				caption : _this.lang.get('permalink'),
2122				submitLabel : false,
2123				content : content,
2124				loadfn : function (dialog)
2125				{
2126					dialog.el.find('.jcm-dialog').addClass('permalink');
2127					dialog.el.find ('input[type="text"]').click (function(){
2128						dialog.el.find ('input[type="text"]').select();
2129					});
2130
2131					dialog.el.find ('input[type="text"]').focus().select();
2132
2133					// copy command
2134					try {
2135						var cptrue = document.execCommand('copy');
2136						if(cptrue){
2137							setTimeout(function(){
2138								dialog.el.find('.cp-stt').fadeIn();
2139							}, 300);
2140						}
2141					} catch (err) {
2142						console.log('Oops, unable to copy');
2143					}
2144
2145
2146					dialog.el.on('click', '.jcm-share-item', function(){
2147						var t = $(this).attr('data-type'),
2148							url2share = null;
2149
2150						switch (t) {
2151							case 'fb':
2152								if(typeof FB!='undefined') {
2153									var fbOptions = {
2154											method: 'feed',
2155											link: url
2156										};
2157
2158									if (!/^\s*$/.test(comment_preview))
2159									{
2160										fbOptions['caption'] = comment_preview;
2161									}
2162
2163									FB.ui(fbOptions, function(response){});
2164
2165									return;
2166								}
2167								
2168								url2share = 'https://www.facebook.com/sharer.php?s=100&p[url]'+encodeURIComponent(url)+(!/^\s*$/.test(comment_preview)?'&p[message]='+encodeURIComponent(comment_preview):'');
2169								break;
2170
2171							case 'tw':
2172								url2share = 'https://twitter.com/intent/tweet?tw_p=tweetbutton'+(!/^\s*$/.test(comment_preview)?'&text='+encodeURIComponent(comment_preview):'')+'&url='+encodeURIComponent(url);
2173								break;
2174
2175							case 'gg':
2176								url2share = 'https://plus.google.com/share?url='+encodeURIComponent(url);
2177								break;
2178						}
2179
2180						if (url2share!=null)
2181						{
2182					        window.open(url2share, 'jcm_sharer', 'top=200,left=200,toolbar=0,status=0,width=600,height=450');
2183						}
2184					});
2185				}
2186			});
2187		});
2188	};
2189
2190	this.user = function(){
2191		var _ob = this,
2192			notifications = [],
2193			notifications_timeoffset = 0;
2194
2195		// notifications
2196		this.notifications = function ()
2197		{
2198			if(settings.member==0 || !settings.alert) return;
2199			$.get(_this.helper.url({task:'user.list_notification', timestamp:notifications_timeoffset}), function(d){
2200				if (d.total > 0)
2201				{
2202					_this.box.find ('.jcm-count-nof').empty().append ('<span>'+d.total+'</span>');
2203					notifications = $.merge (d.notifications, notifications);
2204				}
2205				notifications_timeoffset = d.timestamp;
2206			},'json');
2207		};
2208
2209		this.notifications();
2210		
2211		// refresh after 5mins.
2212		window.setInterval(function(){
2213			_ob.notifications();
2214		}, 300000);
2215
2216		_this.box.on('click', '#jcm-notifications', function(e){
2217			e.preventDefault();
2218			var content  = '<div class="jcm-dg-full">',
2219				nof2html = function (notifications)
2220				{
2221					var html = '';
2222					$.each(notifications, function(k,v){
2223						html+= '<li class="'+(v.unread==1?'unread':'')+'">';
2224							html+= '<a href="'+v.url+'">';
2225								html+= '<span class="_msg">'+v.caption+'</span>';
2226								html+= '<span class="jcm-dg-bullet">&middot;</span>';
2227								html+= '<span class="_date">'+v.created_time+'</span>';
2228								html+= '<span class="jcm-dg-bullet">&middot;</span>';
2229								html+= '<b>'+v.object_name+'</b>';
2230								html+= '<span class="_comment">'+v.comment+'</span>';
2231							html+= '</a>';
2232						html+= '</li>';
2233					});
2234
2235					return html;
2236				};
2237
2238			_this.box.find('.jcm-count-nof').empty();
2239
2240			content+= '<div class="jcm-box">';
2241			if ( notifications.length)
2242			{
2243				content+= '<a href="#" class="nof-mark-all">'+_this.lang.get('mark_all_read')+'</a>';
2244				content+= '<ul class="jcm-list-notifications">';
2245					content+= nof2html(notifications);
2246				content+= '</ul>';
2247			} else {
2248				// load old notification
2249				content+= '<div style="padding:10px;text-align:center;min-height:80px;">'+_this.lang.get('no_notification')+'</div>';
2250				content+= '<ul class="jcm-list-notifications"></ul>';
2251			}
2252			content+= '</div>';
2253
2254			content+= '<a href="#" class="jcm-plg nof-see-all">'+_this.lang.get('all_notification')+'</a>';
2255			content+= '</div>';
2256
2257			new _this.dialog({
2258				caption : _this.lang.get('notification'),
2259				submitLabel : false,
2260				content : content,
2261				loadfn : function (dialog)
2262				{
2263					dialog.el.find('.jcm-dialog').addClass('alert');
2264
2265					var offset = 0,
2266						total  = 0;
2267
2268					dialog.el.on('click','.nof-see-all', function(){
2269						var _el = $(this);
2270
2271						if(_el.hasClass('loading'))
2272						{
2273							return false;
2274						}
2275
2276						_el.addClass('loading');
2277						_el.text(_this.lang.get('please_wait'));
2278
2279						if(offset==0)
2280						{
2281							dialog.el.find('.jcm-box').empty()
2282									.append('<ul class="jcm-list-notifications"></ul>');
2283						}
2284						
2285						$.get(_this.helper.url({task:'user.list_notification', offset:offset, all:1}), function(d){
2286							if(d.total>0)
2287							{
2288								dialog.el.find('.jcm-list-notifications').append (nof2html(d.notifications));
2289							} else {
2290								dialog.el.find('.jcm-dg-content').empty().append(_this.lang.get('no_notification'));
2291							}
2292
2293							_el.removeClass ('loading');
2294							total = d.total;
2295							offset = d.offset+d.limit;
2296							if (offset >= total)
2297							{
2298								_el.fadeOut (function(){
2299									$(this).remove();
2300								});
2301							}
2302
2303							_el.text (_this.lang.get('see_more'));
2304						},'json');
2305					})
2306					.on ('click','.jcm-list-notifications a', function(e){
2307						$(this).parent().removeClass('unread');
2308					})
2309					.on ('click','.nof-mark-all', function(e){
2310						dialog.el.find ('.unread').removeClass ('unread');
2311						$.post ( _this.helper.url({task:'user.mark_read'}) );
2312						$(this).fadeOut (function(){
2313							$(this).remove();
2314						});
2315					});
2316				}
2317			});
2318		});
2319
2320
2321		// user thumbnail
2322		if (settings.profile==1)
2323		{
2324			_this.box.on('click', '#jcm-thumb-edit', function(e){
2325				e.preventDefault();
2326				var content = '<div class="jcm-dg-thumb">';
2327						content+= '<div>';
2328							content+= '<div class="thumb-current"></div>';
2329							content+= '<div class="thumb-row">';
2330								content+= '<label class="thumb-remove"><input type="checkbox" name="remove" value="1" />';
2331								content+= _this.lang.get('thumb_remove_desc')+'</label>';
2332								content+= '<a href="#" class="upload-thumb">'+_this.lang.get('upload_image')+'</a>';
2333							content+= '</div>';
2334							content+= '<div class="clearfix"></div>';
2335						content+= '</div>';
2336						content+= '<div class="thumb-box"></div>';
2337					content+= '</div>';
2338
2339				var cropData = {},
2340					cropFile = null;
2341
2342				new _this.dialog ({
2343					caption: _this.lang.get('thumb_editing'),
2344					submitfn : _this.lang.get('update'),
2345					content : content,
2346					submitfn : function (dialog)
2347					{
2348						var is_del = dialog.el.find('input[name=remove]:checked').length > 0 ? 1 : 0;
2349						if ( cropFile==null && !is_del)
2350						{
2351							// nothing
2352							dialog.off ();
2353							return;
2354						}
2355
2356						var data = new FormData();
2357
2358						if (cropFile!=null)
2359						{
2360							data.append ('file', cropFile);
2361							data.append ('x', cropData.x);
2362							data.append ('y', cropData.y);
2363							data.append ('width', cropData.width);
2364							data.append ('height', cropData.height);
2365						} else {
2366							data.append ('is_del', is_del);
2367						}
2368						
2369						dialog.overlay ();
2370
2371						$.ajax({
2372							url: _this.helper.url ({task:'user.thumb',action:(cropFile!=null?'upload':'remove')}),
2373							type: "POST",
2374							dataType: "json",
2375							data: data,
2376							xhr: function() {
2377								var xhrobj = $.ajaxSettings.xhr();
2378								return xhrobj;
2379							},
2380							success: function(response) {
2381								dialog.unOverlay ();
2382								if (response.status==200)
2383								{
2384									dialog.off ();
2385								} else {
2386									dialog.setError (response.error);
2387								}
2388							},
2389							error: function (xhr, ajaxOptions, thrownError) {
2390								dialog.unOverlay ();
2391						        //if (typeof callback == 'function') 
2392									//callback(xhr.responseJSON);
2393						    },
2394							cache: false,
2395							contentType: false,
2396							processData: false
2397						});
2398					},
2399					loadfn : function (dialog)
2400					{
2401						dialog.el.find('.jcm-dialog').addClass('thumb');
2402						$.get (_this.helper.url({task:'user.thumb',action:'load'}), function(d){
2403							if (d.url!=null)
2404							{
2405								dialog.el.find ('.thumb-current').prepend ('<img src="'+d.url+'" alt="" />');
2406								dialog.el.find ('.jcm-dg-thumb').addClass ('exists');
2407							}
2408						},'json');
2409
2410						dialog.el.on('click', '.upload-thumb', function(){
2411							var _el = $('<input type="file" style="width:1px;height:1px;overflow:hidden" />');
2412								_el.appendTo('body');
2413
2414								_el.on ('change', function(){
2415									var fileObject = $(this)[0].files[0];
2416									var urlObject = window.URL||window.webkitURL;
2417
2418									// check image file
2419									var img_types = ['image/png','image/jpeg','image/jpg','image/gif'];
2420									if ( $.inArray (fileObject.type, img_types) == -1)
2421									{
2422										dialog.setError (_this.lang.get('file_must_img'));
2423										return;
2424									}
2425
2426									// assign file.
2427									dialog.clearError ();
2428									cropFile = fileObject;
2429									
2430									var url = urlObject.createObjectURL(fileObject);
2431
2432									dialog.el.find('.thumb-box').empty().append ('<img src="'+url+'" alt="" />');
2433									dialog.el.find('.thumb-box img').cropper({
2434	  									aspectRatio: 1,
2435	  									rotatable: false,
2436	  									scalable: false,
2437	  									minCropBoxWidth : 200,
2438	  									minCropBoxHeight : 200,
2439										crop: function(e) {
2440											// Output the result data for cropping image.
2441											cropData.x = e.x;
2442											cropData.y = e.y;
2443											cropData.width = e.width;
2444											cropData.height = e.height;
2445										}
2446	  								});
2447								});
2448
2449								_el.trigger('click');
2450						});
2451					}
2452				})
2453			});
2454		}
2455
2456		// user comment
2457		_this.box.on('click','.jcm-user-cm',function(e){
2458			e.preventDefault();
2459			var offset = 0,
2460				uid = $(this).attr('data-id')*1,
2461				content = '<div class="jcm-dg-comments">';
2462					content+= '<div class="user-profile"></div>';
2463					content+= '<div class="user-comments">'+_this.lang.get('please_wait')+'</div>';
2464					content+= '<a href="#" class="load_more_cm">'+_this.lang.get('load_more_cm')+'</a>';
2465				content+= '</div>';
2466
2467			if ( uid < 1 )
2468			{
2469				return;
2470			}
2471
2472			new _this.dialog ({
2473				caption 	: _this.lang.get('comment_title'),
2474				submitLabel : false,
2475				content 	: content,
2476				loadfn 		: function (dialog){
2477					dialog.el.find('.jcm-dialog').addClass('profile');
2478
2479					// load profile
2480					var profile = null;
2481					var loadCm = function ()
2482					{
2483						if (profile==null)
2484						{
2485							$.get (_this.helper.url({task:'user.profile', uid:uid}), function(d){
2486								var html = '<div class="uc-thumb">';
2487										html+= '<img src="'+d.profile.thumb+'" alt="" />';
2488									html+= '</div>';
2489									html+= '<div class="uc-info">';
2490										html+= '<h4>';
2491										if (d.profile.hasOwnProperty("link") && d.profile.link)
2492										{
2493											html+='<a href="'+d.profile.link+'">'+(settings.author_name==1?d.name:d.username)+'</a>';
2494										} else {
2495											html+=settings.author_name==1?d.name:d.username;
2496										}
2497										html+= '</h4>';
2498										html+= '<h6><span class="uc-count-cm">0</span> <span class="_zero">'+_this.lang.get('comment')+'</span><span class="_zerogt" style="display:none">'+_this.lang.get('comments')+'</span></h6>';
2499									html+= '</div>';
2500									html+= '<div class="clearfix"></div>';
2501
2502								dialog.el.find('.user-profile').empty().append (html);
2503
2504								profile = d;
2505								loadCm ();
2506							},'json');
2507
2508							return;
2509						}
2510
2511						$.get (_this.helper.url({task:'user.list_comments',uid:uid,offset:offset}), function(d){
2512							if (d.status==400)
2513							{
2514								dialog.setError (d.error);
2515								return;
2516							}
2517
2518							dialog.el.find('.uc-count-cm').text (d.data.total);
2519							if (d.data.total>1)
2520							{
2521								dialog.el.find('._zero').hide();
2522								dialog.el.find('._zerogt').show();
2523							} else {
2524								dialog.el.find('._zero').show();
2525								dialog.el.find('._zerogt').hide();
2526							}
2527
2528							if ( d.data.comments.length> 0)
2529							{
2530								var html = '';
2531								$.each (d.data.comments, function(k,v){
2532									html+= '<div class="uc-item">';
2533										html+= '<span class="uc-author">'+(settings.author_name==1?profile.name:profile.username)+'</span> ';
2534										html+= '<span class="uc-action">';
2535										if (v.parent_id>0)
2536										{
2537											html+= _this.lang.get('replied_comment');
2538										} else {
2539											html+= _this.lang.get('comment_verb').toLocaleLowerCase();
2540										}
2541										html+= '</span>';
2542										html+= ' '+_this.lang.get('in')+' <a href="'+v.object_url+'"><b>'+v.object_name+'</b></a>';
2543										html+= '<span class="uc-date">
2543'+v.created_time+'</span>';
2544										html+= '<p class="uc-comment">'+v.comment+'</p>';
2545									html+= '</div>';
2546								});
2547
2548								if (offset==0)
2549								{
2550									dialog.el.find('.user-comments').empty().append (html);
2551								} else {
2552									dialog.el.find('.user-comments').append (html);
2553								}
2554							} else {
2555								if (offset==0)
2556								{
2557									dialog.el.find('.user-comments').empty().append (_this.lang.get('no_comment'));
2558								}
2559							}
2560
2561							offset = offset+d.data.limit;
2562							if (offset>= d.data.total)
2563							{
2564								dialog.el.find('.load_more_cm').removeClass('active');
2565								// end;
2566							} else {
2567								dialog.el.find('.load_more_cm').addClass('active');
2568							}
2569						},'json');
2570					};
2571
2572					// first time
2573					loadCm();
2574
2575					dialog.el.on('click', '.load_more_cm.active', function(e){
2576						e.preventDefault();
2577						loadCm();
2578					});
2579				}
2580			});
2581		});
2582
2583		// user logout
2584		_this.box.on('click', '#jcm-u-logout', function(e){
2585			e.preventDefault();
2586			$.get(_this.helper.url({task:'user.logout'}), function(d){
2587				// refresh not reload.
2588				//window.location = window.location;
2589				window.location.reload();
2590			});
2591		});
2592
2593		// user login
2594		_this.box.on('click', '.jcm-u-login', function(e){
2595			e.preventDefault();
2596			if(settings.login_type=='url')
2597			{
2598				window.location=settings.login_url;
2599				return;
2600			}
2601
2602			var content = '<div id="jcm-ulogin-box">';
2603					content+= '<label for="jcm-ulogin-uname">'+_this.lang.get('username')+'</label>';
2604					content+= '<input type="text" id="jcm-ulogin-uname" name="username" />';
2605					content+= '<label for="jcm-ulogin-pw">'+_this.lang.get('password')+'</label>';
2606					content+= '<input type="password" id="jcm-ulogin-pw" name="password" />';
2607				content+= '</div>';
2608
2609			new _this.dialog ({
2610				caption : _this.lang.get('login'),
2611				submitLabel : _this.lang.get('login'),
2612				content : content,
2613				loadfn 	: function (dialog)
2614				{
2615					dialog.el.find('.jcm-dialog').addClass('login');
2616					dialog.el.find('input[name="username"]').trigger('click').focus();
2617				},
2618				submitfn : function (dialog)
2619				{
2620					var request = {
2621							username : dialog.el.find ('input[name="username"]').val(),
2622							password : dialog.el.find ('input[name="password"]').val()
2623						};
2624
2625					if ( /^\s*$/.test(request.username) )
2626					{
2627						dialog.setError (_this.lang.get('username_not_blank'));
2628						return false;
2629					}
2630
2631					if ( request.password=='' )
2632					{
2633						dialog.setError (_this.lang.get('pw_not_blank'));
2634						return false;
2635					}
2636
2637					dialog.clearError ();
2638					dialog.overlay ();
2639
2640					dialog.el.find('.jcm-dg-submit').text (_this.lang.get('please_wait'));
2641
2642					$.post (_this.helper.url({task : 'user.login'}) , request, function(d){
2643						if (d.status==200)
2644						{
2645							dialog.el.find('.jcm-dg-submit').text (_this.lang.get('success'));
2646							//window.location = window.location;
2647							window.location.reload();
2648						} else {
2649							dialog.unOverlay ();
2650							dialog.setError (d.error);
2651							dialog.el.find('.jcm-dg-submit').text (_this.lang.get('login'));
2652						}
2653					}, 'json');
2654				}
2655			});
2656		});
2657
2658		_this.box.on('click','.jcm-u-oauth', function(e){
2659			e.preventDefault();
2660			var type = $(this).attr ('data-action'),
2661				url  = '',
2662				name = '';
2663
2664			switch (type)
2665			{
2666				case 'facebook':
2667					url = _this.helper.url({
2668						task: 'user.oauth',
2669						type:'fb',
2670						popup:1
2671					});
2672					name = "jlex_popup_fb";
2673					break;
2674
2675				case 'google':
2676					url = _this.helper.url({
2677						task: 'user.oauth',
2678						type:'google',
2679						popup:1
2680					});
2681					name = "jlex_popup_google";
2682					break;
2683
2684				case 'twitter':
2685					url = _this.helper.url({
2686						task: 'user.oauth',
2687						type:'twitter',
2688						popup:1
2689					});
2690					name = "jlex_popup_twitter";
2691					break;
2692
2693				case 'vk':
2694					url = _this.helper.url({
2695						task: 'user.oauth',
2696						type:'vk'
2697					});
2698					name = "jlex_popup_vk";
2699					break;
2700			}
2701
2702			window.open(url, name, "width=500, height=350");
2703		});
2704	};
2705
2706	this.listenEvent = function(name,data){
2707		if (typeof CustomEvent == 'undefined') return false;
2708		data = data||{};
2709		var evt = new CustomEvent(name, {detail:data});
2710		window.dispatchEvent(evt);
2711	}
2712
2713	this.events = function()
2714	{
2715		// user events
2716		new _this.user();
2717
2718		window.setInterval(function(){
2719			_this.paginationChild();
2720
2721			if(!$('.jcm-post-body:visible').not('._loaded').length) return;
2722
2723			var _els = $('.jcm-post-body:visible').not('._loaded');
2724			_els.each(function(){
2725				var $i=$(this);
2726
2727				// styles
2728				if(settings.styles!=null)
2729				{
2730					var sid = $i.attr('data-style');
2731					if(settings.styles.hasOwnProperty(sid))
2732					{
2733						$i.addClass('_styled');
2734						$i.attr('style', (settings.styles[sid].css));
2735					}
2736				}
2737
2738				// extend url
2739				$i.find('a').attr('target', '_blank')
2740							.attr('rel', 'nofollow');
2741
2742				// emoji
2743				if(typeof twemoji=='object')
2744				{
2745					twemoji.parse($i[0]);
2746				}
2747
2748				// indent, attach parent user
2749				if(settings.child_style=='1' && $i.find('.jcm-hl').length)
2750				{
2751					var pEl=$i.find('.jcm-hl');
2752					
2753					pEl.attr('href', '#comment-'+pEl.attr('data-id'));
2754					if($('#comment-'+pEl.attr('data-id')).attr('data-parent-id')=='0') pEl.remove();
2755				}
2756
2757				// reaction
2758				if(settings.reactions)
2759				{
2760					var rcEl = $i.parent().next('.jcm-post-footer').find('.jcm-reaction-data'),
2761						_cmid = rcEl.parents('.jcm-voting').attr('data-id'),
2762						_firstE = settings.reactions[Object.keys(settings.reactions)[0]],
2763						_total = 0,
2764						_removeReact = function(ignore)
2765						{
2766							rcEl.find('._react').removeClass('active').removeAttr('style').text(_firstE.label);
2767							rcEl.find('.reaction-btn').removeClass('active');
2768							
2769							if(_total>0)
2770							{
2771								_total-=1;
2772								rcEl.find('.react-total').text(_total);
2773								if(_data!=null) _data.set = null;
2774
2775								if(_total<1) rcEl.find('.react-stic').remove();
2776							}
2777
2778							if(typeof ignore=='undefined')
2779							{
2780								$.post(_this.helper.url({task:'item.vote'}) ,{id:_cmid,point:0});
2781							}
2782						},
2783						_setReact = function(id)
2784						{
2785							var _elc = rcEl.find('.reaction-btn[data-id='+id+']');
2786
2787							if(_elc.hasClass('active'))
2788							{
2789								_removeReact();
2790								return;
2791							} 
2792
2793							_elc.addClass('active');
2794							_elc.siblings().removeClass('active');
2795
2796							rcEl.find('._react').addClass('active')
2797									.text((settings.reactions[id]).label)
2798									.css('color','#'+(settings.reactions[id]).color);
2799							
2800							try {
2801								if (_data.set>0 && _total==1)
2802									rcEl.find('.react-stic').remove();
2803							} catch(err) {}
2804
2805							if(_data==null || _data.set==null)
2806							{
2807								_total+=1;
2808								rcEl.find('.react-total').text(_total);
2809							}
2810							
2811							if(_data==null) _data={};
2812							_data.set=id;
2813
2814							$.post(_this.helper.url({task:'item.vote'}) ,{id:_cmid,point:id}, function(d){
2815								if (d.status==400)
2816								{
2817									alert(d.error);
2818									_removeReact(true);
2819								}
2820							},'json');
2821						},
2822						_data 	= rcEl.text();
2823
2824					try {
2825					    _data = $.parseJSON(_data);
2826					} catch(err){ _data = null; }
2827
2828
2829					if(_data!=null)
2830					{
2831						rcEl.empty().removeAttr('style');
2832						rcEl.append('<span class="_tbox"></span>');
2833						rcEl.find('._tbox').append('<a href="#" class="_react"></a>');
2834
2835						var action = _firstE.label;
2836						if(_data!=null && _data.set!=null && _data.set>1)
2837						{
2838							if(settings.reactions.hasOwnProperty(_data.set))
2839							{
2840								action=settings.reactions[_data.set].label;
2841								rcEl.find('._react').addClass('active').css('color','#'+settings.reactions[_data.set].color);
2842							}
2843						}
2844
2845						rcEl.find('._react').text(action);
2846
2847						// list reactions
2848						rcEl.find('._tbox').append('<div class="react-box"></div>');
2849
2850						var _idexReact = 1;
2851						$.each(settings.reactions, function(k,v){
2852							var _set = _data!=null&&_data.set!=null?_data.set:-1,
2853								_elc = $('<span class="reaction-btn'+(_set==k?' active':'')+'" data-id="'+k+'" style="transition-delay:'+(_idexReact*0.03)+'s;"><span class="_act"><img src="'+v.icon+'" alt="" /></span><span class="_label">'+v.label+'</span></span>');
2854								_elc.on('click', '._act', function(e){
2855									e.preventDefault();
2856									_setReact(k);
2857								});
2858
2859								_elc.appendTo(rcEl.find('.react-box'));
2860								_idexReact++;
2861						});
2862
2863						var reactBoxWid = (_idexReact-1)*32+(_idexReact-2)*10+6;
2864						rcEl.find('.react-box').css('width', reactBoxWid+'px');
2865
2866						try {
2867							if(reactBoxWid+10>$(window).width()-rcEl.offset().left)
2868							{
2869								var reactBoxOff=reactBoxWid+10-$(window).width()+rcEl.offset().left;
2870								rcEl.find('.react-box').css('left', '-'+reactBoxOff+'px');
2871							}
2872						} catch(err){};
2873
2874						
2875						if(_data!=null && _data.list!=null)
2876						{
2877							var _html = '';
2878							_html+= '<div class="react-stic">';
2879								$.each(_data.list, function(k,v){
2880									if(v<=0) return true;
2881									var _react = settings.reactions[k];
2882									if(typeof _react=='undefined')
2883									{
2884										return true;
2885									}
2886
2887									_html+= '<span class="react-set" data-id="'+k+'" data-count="'+v+'">';
2888										_html+= '<span class="react-icon"><img src="'+_react.icon+'" alt="" /></span>';
2889										_html+= '<span class="react-count">'+_react.label+'</span>';
2890									_html+= '</span>';
2891									_total+= v*1;
2892								});
2893								if(_total>0)
2894									_html+= '<span class="react-total">'+_total+'</span>';
2895							_html+= '</div>';
2896
2897							rcEl.append(_html);
2898							if(_total<1) rcEl.find('.react-stic').remove();
2899						}
2900
2901						// event
2902						rcEl.on('click', '._react', function(e){
2903							e.preventDefault();
2904							$(this).hasClass('active') ? _removeReact():_setReact(Object.keys(settings.reactions)[0]);
2905						});
2906
2907						var _cache={},
2908							__request=null;
2909						rcEl.find('.react-set')
2910						.mouseenter(function(){
2911							var __id = $(this).attr('data-id'),
2912								__el = $(this).find('.__extra'),
2913								_toHtml = function(id)
2914								{
2915									var dt 		= _cache[id],
2916										_else 	= dt.total*1,
2917										_html 	= [];
2918
2919									if(dt.you==1)
2920									{
2921										_html.push(_this.lang.get('you'));
2922										_else-=1;
2923									}
2924
2925									if(dt.members!=null && dt.members.length)
2926									{
2927										$.each(dt.members,function(k,v){
2928											_html.push(v);
2929										});
2930										_else-=dt.members.length;
2931									}
2932
2933									if(_else>0)
2934									{
2935										if(_else==1)
2936										{
2937											_html.push(_this.lang.get(!_html.length?'more_one_pp_line':'more_one_pp'));
2938										} else {
2939											_html.push(_this.lang.get((!_html.length?'more_many_pp_line':'more_many_pp'),_else));
2940										}
2941									}
2942
2943									var _output = '<ul><li>'+_html.join('</li><li>')+'</li></ul>';
2944									return _output;
2945								};
2946
2947							if($(this).attr('data-total')*1<1) return false;
2948
2949							if(__el.length)
2950							{
2951								__el.show();
2952							} else {
2953								$(this).append('<div class="__extra"></div>');
2954								__el = $(this).find('.__extra');
2955							}
2956
2957							//import content
2958							__el.empty();
2959							if(_cache.hasOwnProperty(__id))
2960							{
2961								__el.append(_toHtml(__id));
2962							} else {
2963								__el.append('<span>'+_this.lang.get('please_wait')+'</span>');
2964								__request = $.get(_this.helper.url({task:'others.reaction_stic'}),{cmid:_cmid,id:__id},function(d){
2965									if(d.status==200)
2966									{
2967										_cache[__id]=d.data;
2968										__el.empty().append(_toHtml(__id));
2969									}
2970								},'json');
2971							}
2972						})
2973						.mouseleave(function(){
2974							$(this).find('.__extra').hide();
2975							if(__request!=null) __request.abort();
2976						});
2977					}
2978				}
2979
2980				// auto open form
2981				if(settings.openform!='0')
2982				{
2983					var $pi=$i.closest('li.jcm-block');
2984					if($pi.attr('data-parent-id')==0)
2985					{
2986						$pi.find('>.jcm-post-content>.jcm-post-footer .jcm-reply').trigger('click', false);
2987					}
2988				}
2989
2990				// gallery
2991				if(typeof lightGallery!="undefined")
2992				{
2993					if(!$i.next('.jcm-images-slideshow').length) return;
2994					lightGallery($i.next('.jcm-images-slideshow')[0]);
2995				}
2996			});	
2997
2998			// read more
2999			if(settings.readmore && typeof $.fn.readmore=='function')
3000			{
3001				window.setTimeout(function(){
3002					var s=function(){
3003						_els.each(function(){
3004							$(this).css('height','auto');
3005							if(!$(this).find('.__i').length)
3006							{
3007								$(this).wrapInner('<div class="__i"></div>');
3008							}
3009							
3010							$(this).find('.__i').removeAttr('style').css('height', $(this).height());
3011						});
3012
3013						try {
3014							_els.readmore('destroy');
3015						} catch(error) {}
3016
3017						_els.readmore({
3018							speed:75,
3019							moreLink: '<a class="jcm-readmore jcm-i3" href="#"><span>'+_this.lang.get('readmore')+'</span></a>',
3020							lessLink: '<a class="jcm-readless jcm-i3" href="#"><span>'+_this.lang.get('close')+'</span></a>'
3021						});
3022					};
3023
3024					s();
3025				}, 1000);
3026			}
3027
3028			_els.addClass('_loaded');
3029		},500);
3030
3031		// for element editor
3032		var _elEditable = _this.box.find('.jcm-textarea')[0];
3033
3034		if(_this.browser.contenteditable==null && _elEditable)
3035		{
3036			_this.browser.contenteditable = typeof(_elEditable.contentEditable) == 'undefined' ? false : true;
3037		}
3038
3039		if(_this.browser.contenteditable==false)
3040		{
3041			var _elReplace = '<textarea class="jcm-textarea" name="comment"></textarea>';
3042			_this.box.find('.jcm-textarea').replaceWith(_elReplace);
3043		}
3044
3045		$('.jcm-terms').click(function(e){
3046			e.preventDefault();
3047			new _this.dialog({
3048				caption : _this.lang.get('cm_terms'),
3049				content : _this.lang.get('please_wait'),
3050				submitLabel: false,
3051				cancelLabel: 'Ok',
3052				loadfn: function(dialog){
3053					dialog.el.find('.jcm-dialog').addClass('terms');
3054					$.get(_this.helper.url({task:'others.terms'}), function(d){
3055						dialog.el.find('.jcm-dg-content').empty().append(d.content);
3056					}, 'json');
3057				}
3058			});
3059		});
3060
3061		_this.box
3062		.on('click', '.jcm-reply', function(e, fa){
3063			e.preventDefault();
3064			let root_id = $(this).attr('data-root')*1;
3065			if(typeof fa=='undefined') fa=true;
3066
3067			if(root_id==0 && settings.openform=='bottom')
3068			{
3069				let fc=$(this).closest('.jcm-post-content');
3070
3071				if(fc.find('>.jcm-reply-form').length)
3072				{
3073					if(fc.find('.jcm-btn-emoticon').hasClass('active'))
3074						fc.find('.jcm-btn-emoticon').trigger('click');
3075				} else {
3076					let parent_id = $(this).attr('data-pid')*1;
3077					fc.append('<div class="jcm-reply-form"></div>');
3078					_this.createCmform(fc.find('.jcm-reply-form'), {parent_id:parent_id, root_id:$(this).attr('data-root')}, fa);
3079				}
3080				
3081				if(fa)
3082				{
3083					let fcf=fc.find('>.jcm-reply-form .jcm-form-cp');
3084					fcf.find('.jcm-textarea').focus();
3085					$("html, body").animate({scrollTop:fcf.offset().top-50}, 500);
3086				}
3087			} else {
3088				let fc=$(this).closest('.jcm-post-footer');
3089
3090				if(fc.find('.jcm-reply-form').length)
3091				{
3092					if(root_id==0 && settings.openform=='top')
3093					{
3094						if(fa) fc.find('.jcm-textarea').focus();
3095					} else {
3096						fc.find('.jcm-reply-form').toggle();
3097					}
3098
3099					if(fc.find('.jcm-btn-emoticon').hasClass('active'))
3100						fc.find('.jcm-btn-emoticon').trigger('click');
3101				} else {
3102					let parent_id = $(this).attr('data-pid')*1;
3103					fc.append('<div class="jcm-reply-form"></div>');
3104					_this.createCmform(fc.find('.jcm-reply-form'), {parent_id:parent_id, root_id:$(this).attr('data-root')}, fa);
3105				}
3106			}
3107
3108			if(root_id==0 && $.inArray(settings.openform, ['bottom', 'top'])!=-1)
3109			{
3110				$(this).addClass('active');
3111			} else {
3112				$(this).toggleClass('active');
3113			}
3114		})
3115		.on('click', '.jcm-edit', function(e){
3116			e.preventDefault();
3117			var id = $(this).parent().attr ('data-id') * 1,
3118				bodyCm = $(this).closest('.jcm-post-content');
3119
3120			$(this).closest('.jcm-dropdown').toggleClass('active');
3121			$('#comment-'+id).addClass('editing');
3122
3123			$.get(_this.helper.url({task:'item.edit',id:id}) , function(d){
3124				if(d.status == 200)
3125				{
3126					bodyCm.children('.jcm-comment-edit').remove();
3127					bodyCm.children('.jcm-flex-content').hide();
3128
3129					// create form
3130					bodyCm.prepend ('<div class="jcm-comment-edit"></div>');
3131					_this.createCmform(bodyCm.children ('.jcm-comment-edit'), d.data);
3132				}
3133			}, 'json');
3134		})
3135		.on('click', '.jcm-delete', function(e){
3136			e.preventDefault();
3137			var id = $(this).parent().attr('data-id')*1;
3138
3139			$(this).closest('.jcm-dropdown').toggleClass('active');
3140
3141			var dialog = new _this.dialog({
3142					caption: _this.lang.get('warning'),
3143					submitLabel : _this.lang.get('delete'),
3144					content : _this.lang.get('delete_confirm'),
3145					submitfn : function(dialog)
3146					{
3147						dialog.overlay();
3148						$.post(_this.helper.url ({task:'item.remove',id:id}) , function(d){
3149							if(d.status==200)
3150							{
3151								_this.box.find('#comment-'+id).fadeOut(function(){
3152									$(this).remove();
3153								});
3154								dialog.off();
3155							} else {
3156								dialog.unOverlay();
3157								dialog.setError(d.error);
3158							}
3159						}, 'json');
3160					},
3161					loadfn:function(dialog){
3162						dialog.el.find('.jcm-dialog').addClass('warning');
3163					}
3164				});
3165		})
3166		.on('click', '.jcm-state', function(e){
3167			e.preventDefault();
3168			var _el = $(this),
3169				id = _el.parent().attr('data-id')*1,
3170				state = _el.hasClass('_off')?0:1;
3171
3172			_el.addClass('_loading');
3173
3174			$.post(_this.helper.url({task:'item.state',id:id,state:state}), function(d){
3175				_el.removeClass('_loading');
3176				if(d.status==200)
3177				{
3178					if(state==0)
3179					{
3180						_this.box.find('#comment-'+id).addClass('jcm-unpublished');
3181					} else {
3182						_this.box.find('#comment-'+id).removeClass('jcm-unpublished');
3183					}
3184					_el.closest('.jcm-dropdown').toggleClass('active');
3185					_el.toggleClass('_on').toggleClass('_off');
3186				} else {
3187					alert(d.error);
3188				}
3189			}, 'json');
3190		})
3191		.on('click', '.jcm-feature', function(e){
3192			e.preventDefault();
3193			var _el = $(this),
3194				id = _el.parent().attr('data-id')*1,
3195				state = _el.hasClass('_off')?0:1;
3196
3197			_el.addClass('_loading');
3198
3199			$.post(_this.helper.url({task:'item.feature',id:id, state:state}) , function(d){
3200				_el.removeClass('_loading');
3201				if(d.status==200)
3202				{
3203					if(state==1)
3204					{
3205						_this.box.find ('#comment-'+id).addClass ('jcm-featured');
3206					} else {
3207						_this.box.find ('#comment-'+id).removeClass ('jcm-featured');
3208					}
3209					_el.closest('.jcm-dropdown').toggleClass ('active');
3210					_el.toggleClass ('_on').toggleClass ('_off');
3211				} else {
3212					alert (d.error);
3213				}
3214			}, 'json');
3215		})
3216		.on('click', '.jcm-report', function(e)
3217		{
3218			e.preventDefault ();
3219			var _el = $(this),
3220				id = _el.attr ('data-id')*1,
3221				request = {id:id};
3222
3223			if(_el.hasClass('loading')) return false;
3224
3225			if(_el.hasClass('active'))
3226			{
3227				// remove
3228				var dialog = new _this.dialog ({
3229					caption : _this.lang.get('reporting'),
3230					content : _this.lang.get('cancel_reporting'),
3231					submitLabel : _this.lang.get('ignore'),
3232					loadfn:function(dialog){
3233						dialog.el.find('.jcm-dialog').addClass('cancel-report');
3234					},
3235					submitfn : function (dialog)
3236					{
3237						dialog.el.find('.jcm-dg-content').empty().append ('<span>'+_this.lang.get('please_wait')+'</span>');
3238						_el.addClass ('loading');
3239
3240						dialog.overlay();
3241						$.post(_this.helper.url({task:'report.ignore'}), request, function (d){
3242							_el.removeClass('loading');
3243							dialog.unOverlay ();
3244							if (d.status==200)
3245							{
3246								_el.removeClass('active');
3247								dialog.off();
3248							} else {
3249								dialog.el.find('.jcm-dg-content').empty().append(d.error);
3250								dialog.el.find('.jcm-dg-submit').remove();
3251							}
3252						}, 'json');
3253					}
3254				});
3255			} else {
3256				// post
3257				var content ='<div class="jcm-report-box">';
3258					content+='<label>'+_this.lang.get('report_reason')+'</label><textarea></textarea>';
3259
3260				if(settings.member==0)
3261				{
3262					// guest, request name & email
3263					content+= '<label>'+_this.lang.get('your_name')+'</label>';
3264					content+= '<input type="text" name="guest_name" value="'+_this.browser.guest.name+'">';
3265					content+= '<label>'+_this.lang.get('your_email')+'</label>';
3266					content+= '<input type="email" name="guest_email" value="'+_this.browser.guest.email+'">';
3267				}
3268
3269				content+='</div>';
3270
3271				new _this.dialog({
3272					caption : _this.lang.get('reporting'),
3273					content : content,
3274					submitLabel : _this.lang.get('report'),
3275					loadfn: function(dialog){
3276						dialog.el.find('.jcm-dialog').addClass('report');
3277					},
3278					submitfn : function(dialog)
3279					{
3280						var msg = dialog.el.find('textarea').val();
3281						dialog.clearError();
3282
3283						if(/^\s*$/.test(msg))
3284						{
3285							dialog.setError(_this.lang.get('fill_your_report'));
3286							dialog.el.find('textarea').focus();
3287							return;
3288						}
3289
3290						if(settings.member==0)
3291						{
3292							request.name = dialog.el.find('input[name="guest_name"]').val();
3293							request.email = dialog.el.find('input[name="guest_email"]').val();
3294							if(/^\s*$/.test(request.name))
3295							{
3296								dialog.el.find('input[name="guest_name"]').focus();
3297								return;
3298							}
3299
3300							if(/^\s*$/.test(request.email))
3301							{
3302								dialog.el.find('input[name="guest_email"]').focus();
3303								return;
3304							}
3305						}
3306
3307						dialog.el.find('.jcm-dg-content').find('.jcm-report-box').hide();
3308						dialog.el.find('.jcm-dg-content').append('<span class="_loading">'+_this.lang.get('please_wait')+'</span>');
3309
3310						request.msg = msg;
3311						_el.addClass('loading');
3312						dialog.overlay();
3313
3314						$.post(_this.helper.url({task:'report.post'}), request, function (d){
3315							dialog.unOverlay();
3316							_el.removeClass('loading');
3317							if(d.status==200)
3318							{
3319								_el.addClass('active');
3320								dialog.el.find('.jcm-dg-content').empty().append( '<span>'+_this.lang.get('thanks_feedback')+'</span>' );
3321								dialog.el.find('.jcm-dg-submit').remove();
3322								window.setTimeout(function(){
3323									dialog.off();
3324								}, 3000);
3325							} else {
3326								dialog.el.find('.jcm-dg-content').find ('.jcm-report-box').show ();
3327								dialog.el.find('.jcm-dg-content').find ('._loading').remove();
3328								dialog.setError(d.error);
3329							}
3330						}, 'json');
3331					}
3332				});
3333			}
3334		})
3335		.on ('mouseenter', '.jcm-tooltip', function(){
3336			if(!$(this).find('.jcm-tooltip-body').length )
3337	        {
3338	        	var content = $(this).attr('title'),
3339	        		_el = $('<span class="jcm-tooltip-body">'+content+'</span>');
3340	        	$(this).append(_el);
3341	        	$(this).removeAttr('title');
3342
3343	        	var _elWidth = typeof $.fn.outerWidth=='function'?_el.outerWidth():_el.width();
3344	     		if ( _elWidth>=120 )
3345	     		{
3346	     			_el.css('white-space', 'normal');
3347	     			_el.css('width', '120px');
3348	     		}
3349	        	_el.css('margin-left', (_elWidth/-2)+'px');
3350	        }
3351		});
3352
3353		// voting feature
3354		if(!settings.reactions)
3355		{
3356			_this.box.on('click','.jcm-vote-up .jcm-control, .jcm-vote-down .jcm-control', function (e){
3357				e.preventDefault();
3358				var	_el = $(this),
3359					_parent = _el.closest('.jcm-voting');
3360					cm_id = _parent.attr('data-id') * 1,
3361					point 	= _el.parent().attr('data-action')=='upvote'?1:-1;
3362
3363				if(_el.hasClass('active')) point=0;
3364				if(_el.hasClass('disabled')) return;
3365				_el.addClass('disabled');
3366
3367				$.post(_this.helper.url({task:'item.vote'}), {id:cm_id,point:point}, function(d){
3368					_el.removeClass('disabled');
3369
3370					if(typeof d!='object') return;
3371					if(d.status==400)
3372					{
3373						alert(d.error);
3374						return;
3375					}
3376
3377					_parent.find('.jcm-vote-up .jcm-control, .jcm-vote-down .jcm-control').removeClass('active');
3378					switch (d.data.vote*1)
3379					{
3380						case 1:
3381							_parent.find('.jcm-vote-up .jcm-control').addClass('active');
3382							break;
3383
3384						case -1:
3385							_parent.find('.jcm-vote-down .jcm-control').addClass('active');
3386							break;
3387					}
3388
3389					// update voting point
3390					var oldPointUp = _parent.find('.jcm-vote-up .jcm-count').text() * 1,
3391						oldPointDown = _parent.find('.jcm-vote-down .jcm-count').text() * 1;
3392
3393					if(d.data.up!=0)
3394					{
3395						_parent.find('.jcm-vote-up .jcm-count').text( oldPointUp+d.data.up*1 );
3396						if (oldPointUp+d.data.up*1==0)
3397						{
3398							_parent.find('.jcm-vote-up').addClass('count-0');
3399						} else {
3400							_parent.find('.jcm-vote-up').removeClass('count-0');
3401						}
3402					}
3403
3404					if(d.data.down!=0)
3405					{
3406						_parent.find('.jcm-vote-down .jcm-count').text( oldPointDown+d.data.down*1 );
3407						if(oldPointDown+d.data.down*1==0)
3408						{
3409							_parent.find('.jcm-vote-down').addClass('count-0');
3410						} else {
3411							_parent.find('.jcm-vote-down').removeClass('count-0');
3412						}
3413					}
3414				},'json');
3415			});
3416		}
3417
3418		// sort comment
3419		var urlRoot = settings.url;
3420		_this.box.on('click', '.jcm-sortby a', function(e){
3421			e.preventDefault();
3422			var _el  = $(this),
3423				sort = _el.attr('data-sort');
3424
3425			if(_el.hasClass('active'))
3426			{
3427				_el.closest('.jcm-dropdown').removeClass('active');
3428				return false;
3429			}
3430
3431			_el.addClass('active');
3432			_el.parent().siblings().find('a').removeClass('active');
3433
3434			if( _el.closest('.jcm-dropdown').find('.jcm-dropdown-val').length)
3435			{
3436				_el.closest('.jcm-dropdown').find('.jcm-dropdown-val').text(_el.text());
3437			}
3438			_el.closest('.jcm-dropdown').removeClass('active');
3439
3440			// reload comments
3441			_this.config.sort = sort;
3442			_this.config.page_comment = 1;
3443
3444			_this.reload ({unwrap:0}, function(d){
3445				_this.config.timestamp = d.timestamp;
3446				_this.timestamp [0] = d.timestamp;
3447
3448				_this.box.find ('#jcm-comments').empty ().append (d.html);
3449				_this.box.find ('.jcm-root-page a').each (function(){
3450					var page = $(this).attr ('data-page') * 1,
3451						newUrl = '';
3452
3453					if ( /page_comment=[1-9][0-9]*/.test(urlRoot) )
3454					{
3455						newUrl = urlRoot.replace (/page_comment=[1-9][0-9]*/,'page_comment=' + page);
3456					} else {
3457						newUrl = ( urlRoot.indexOf ('?')==-1 ? '?' : '&' ) + 'page_comment=' + page;
3458					}
3459
3460					$(this).attr('href', newUrl);
3461				});
3462			});
3463		})
3464		.on('click','.jcm-subscribe', function(e){
3465			e.preventDefault();
3466			var _el = $(this);
3467
3468			if(_el.hasClass('_on'))
3469			{
3470				var dialog = new _this.dialog ({
3471					caption 	: _this.lang.get('unsubscribe'),
3472					content 	: _this.lang.get('unsubscribe_confirm'),
3473					submitLabel : 'Ok',
3474					submitfn 	: function (dialog)
3475					{
3476						var request = {key:_this.config.key};
3477
3478						if ( typeof _el.attr('data-hash') != 'undefined' )
3479						{
3480							request.hash = _el.attr('data-hash');
3481						}
3482
3483						dialog.overlay ();
3484
3485						$.post (_this.helper.url({task:'subscribe.remove'}) ,request , function(d){
3486							dialog.unOverlay ();
3487							if (d.status==200)
3488							{
3489								var msg = settings.subscribe_verify==1 ? _this.lang.get('subscribe_verify') : _this.lang.get('unsubscribe_msg');
3490								dialog.el.find ('.jcm-dg-content').empty().append (msg);
3491								
3492								_el.removeClass('_on')
3493									.addClass('_off');
3494								_el.removeAttr ('data-hash');
3495
3496								window.setTimeout (function(){
3497									dialog.off ();
3498								}, 30000);
3499							} else if (d.status==400)
3500							{
3501								dialog.el.find ('.jcm-dg-content').empty().append (d.error);
3502							}
3503							dialog.el.find ('.jcm-dg-submit').remove();
3504						},'json')
3505					}
3506				});
3507			} else {
3508				var dialog = new _this.dialog ({
3509					caption 	: _this.lang.get('subscribe'),
3510					content 	: '<span>'+_this.lang.get('please_wait')+'</span>',
3511					submitLabel : _this.lang.get('subscribe'),
3512					loadfn 		: function (dialog)
3513					{
3514						$.get (_this.helper.url({task:'subscribe.suggest'}),{key:_this.config.key}, function(d){
3515							if (d.status==200)
3516							{
3517								if (d.data.followed==1)
3518								{
3519									var msg = _this.lang.get('followed_status');
3520									dialog.el.find ('.jcm-dg-content').empty().append (msg);
3521									dialog.el.find ('.jcm-dg-submit').remove();
3522									_el.addClass('_on')
3523										.removeClass('_off');
3524								} else {
3525									var html = '<span>'+_this.lang.get('fill_your_info')+'</span><br/>';
3526										html+= '<span>'+_this.lang.get('your_name')+'</span><input type="text" name="name" value="'+d.data.name+'" />';
3527										html+= '<span>'+_this.lang.get('your_email')+'</span><input type="email" name="email" value="'+d.data.email+'" />';
3528
3529									dialog.el.find ('.jcm-dg-content').empty().append (html);
3530								}
3531							} else if (d.status==400) {
3532								dialog.el.find ('.jcm-dg-content').empty().append (d.error);
3533							}
3534						},'json');
3535					},
3536					submitfn 	: function (dialog)
3537					{
3538						var _nameEl = dialog.el.find ('[name=name]'),
3539							_emailEl = dialog.el.find ('[name=email]');
3540
3541						if ( /^\s*$/.test(_nameEl.val()) )
3542						{
3543							_nameEl.focus();
3544							return false;
3545						}
3546
3547						if ( /^\s*$/.test(_emailEl.val) )
3548						{
3549							_emailEl.focus();
3550							return false;
3551						}
3552
3553						dialog.el.find ('.jcm-dg-submit,.jcm-dg-cancel').attr('disabled','disabled');
3554
3555						$.post (_this.helper.url({task:'subscribe.add'}), {key:_this.config.key,name:_nameEl.val(), email:_emailEl.val()}, function(d){
3556							dialog.el.find ('.jcm-dg-submit,.jcm-dg-cancel').removeAttr('disabled');
3557							if ( d.status== 200)
3558							{
3559								var msg = _this.lang.get('followed_status');
3560
3561								_el.addClass('_on')
3562									.removeClass('_off');
3563								if (d.hash!=1)
3564								{
3565									_el.attr ('data-hash', d.hash);
3566								}
3567
3568								dialog.el.find ('.jcm-dg-content').empty().append (msg);
3569								dialog.el.find ('.jcm-dg-submit').remove();
3570
3571								window.setTimeout (function(){
3572									dialog.off ();
3573								}, 3000);
3574							} else if (d.status==400)
3575							{
3576								dialog.el.find ('.jcm-dg-content').empty().append (d.error);
3577								dialog.el.find ('.jcm-dg-submit').remove();
3578							}
3579						},'json');
3580					}
3581				});
3582			}
3583		})
3584		.on('click','.jcm-task-collapse,.jcm-task-expand', function(e){
3585			e.preventDefault();
3586			var _el = $(this).closest('.jcm-block');
3587			_el.toggleClass('jcm-collapse');
3588			_el.toggleClass('jcm-expand');
3589		})
3590		.on('click', '.jcm-toggle-all', function(e){
3591			e.preventDefault();
3592			_this.box.find('.jcm-block')
3593				.removeClass('jcm-collapse jcm-expand')
3594				.addClass($(this).hasClass('_on')?'jcm-collapse':'jcm-expand');
3595
3596			$(this).toggleClass('_on _off');
3597		})
3598		.on('click', '.jcm-dropdown-toggle', function(e){
3599			e.preventDefault();
3600			var _el = $(this).parent();
3601			_el.toggleClass ('active');
3602		})
3603		.on('click', '.jcm-map-dest', function(e){
3604			e.preventDefault ();
3605
3606			var _el = $(this),
3607				location = _el.attr("data-location").split(",");
3608
3609			dialogMap = new _this.dialog ({
3610				caption : _el.text(),
3611				content : '<div class="mapContent">'+_this.lang.get('please_wait')+'</div>',
3612				submitLabel : false,
3613				submitfn : function (dialog)
3614				{
3615					
3616				},
3617				cancelfn : function (dialog)
3618				{},
3619				loadfn : function (dialog)
3620				{
3621					window.setTimeout (function(){
3622						var mapLoader = new google.maps.Map( dialog.el.find('.mapContent')[0] ,{
3623							    center: new google.maps.LatLng(location[1], location[0]),
3624							    zoom: 13
3625							}),
3626							html = '<div class="infowindow-content">';
3627								html+= '<img src="" width="16" height="16" class="_icon" alt="">';
3628								html+= '<span class="_name"  class="title"></span><br>';
3629								html+= '<span class="_address"></span></div>';
3630
3631							dialog.el.find('.jcm-dg-content').prepend(html);
3632
3633							var infowindow = new google.maps.InfoWindow(),
3634					        	infowindowContent = dialog.el.find('.infowindow-content');
3635					        	infowindow.setContent(infowindowContent[0]);
3636
3637					        var marker = new google.maps.Marker({
3638									map: mapLoader,
3639									anchorPoint: new google.maps.Point(0, -29)
3640						        });
3641
3642					        var marker_loc  = new google.maps.LatLng(location[1], location[0]);
3643
3644							marker.setPosition(marker_loc);
3645							marker.setVisible(true);
3646
3647							// infoWindow
3648							infowindowContent.find('._name').text(_el.text());
3649							infowindowContent.find('._address').text(_el.attr("data-address"));
3650							infowindowContent.find('._icon').attr("src", decodeURIComponent(_el.attr("data-img")));
3651							infowindow.open(mapLoader, marker);
3652					}, 300);
3653				}
3654			});
3655		})
3656		.on('click', '.jcm-files-attached ._detail', function(e){
3657			e.preventDefault();
3658			$(this).toggleClass('_off')
3659					.toggleClass('_on');
3660		});
3661
3662		// dropdown
3663		$(document).click(function(e){
3664			if($(e.target).closest('.jcm-dropdown').length)
3665			{
3666				var _el = $(e.target).closest('.jcm-dropdown');
3667				_this.box.find('.jcm-dropdown.active').not(_el).removeClass('active');
3668			} else {
3669				_this.box.find('.jcm-dropdown.active').removeClass('active');
3670			}
3671		});
3672
3673		// sharing
3674		_this.sharefn();
3675
3676		// responsive
3677		var jcmrs = function()
3678		{
3679			_this.box.width()>450?_this.box.removeClass('jcm-xsmall'):_this.box.addClass('jcm-xsmall');
3680
3681			// player
3682			var plyrs = null;
3683			if(plyrs!=null) clearInterval(plyrs);
3684			plyrs=setInterval(function(){
3685				if(!$('.jcm-player').length) return;
3686
3687				$('.jcm-player').each(function(){
3688					var pel=$(this);
3689					
3690					pel.find('.jcm-player-main').css('height', (pel.width()*9/16-1)+'px');
3691
3692					pel.find('.jcm-player-main').css('background-image', 'url('+pel.find('.jcm-player-main').attr('data-image')+')');
3693					pel.find('.jcm-player-main').click(function(e){
3694						e.preventDefault();
3695						if($(this).hasClass('active')) return;
3696						$(this).addClass('active');
3697						
3698						pel.find('.jcm-player-main').css('background-image','');
3699						pel.find('.jcm-player-main').append('<iframe width="853" height="480" src="'+pel.find('.jcm-player-main').attr('data-embed')+'" frameborder="0" allowfullscreen></iframe>');
3700					});
3701				});
3702			}, 1000);
3703		};
3704
3705		$(window).resize(function(){
3706			jcmrs();
3707		});
3708		jcmrs();
3709
3710		// ie support
3711		(function(){
3712			function CustomEvent(event, params){
3713				params = params || { bubbles: false, cancelable: false, detail: undefined };
3714				var evt = document.createEvent( 'CustomEvent' );
3715				evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
3716				return evt;
3717			}
3718
3719			CustomEvent.prototype = window.Event.prototype;
3720			window.CustomEvent = CustomEvent;
3721		})();
3722
3723		// refresh - live feature
3724		if(settings.refresh>0)
3725		{
3726			_this.box.find('.jcm-refresh').addClass('active');
3727
3728			var timeSub = settings.refresh*60;
3729			window.setInterval(function(){
3730				if (timeSub<=0)
3731				{
3732					timeSub = settings.refresh*60;
3733
3734					var _config = {
3735							timestamp : 0,
3736							timestamp_offset : _this.timestamp.hasOwnProperty(0) ? _this.timestamp[0] : _this.config.timestamp,
3737							sort : 'desc',
3738							page_comment: 1
3739						};
3740
3741					_this.box.find('.jcm-refresh').addClass ('_loading');
3742					_this.reload (_config, function(d){
3743						_this.timestamp [0] = d.timestamp;
3744						if ( !_this.box.find('.jcm-root').length )
3745						{
3746							_this.box.find('#jcm-comments').append ('<ul class="jcm-root"></ul>');
3747						}
3748						_this.box.find('.jcm-root').prepend (d.html);
3749
3750						// clear cache
3751						_this.tmpCache = {};
3752						_this.box.find('.jcm-refresh').removeClass ('_loading');
3753					});
3754				}
3755
3756				var time_m = parseInt(timeSub/60),
3757					time_s = timeSub - time_m * 60;
3758
3759				var time_fm = (time_m<10 ? '0'+time_m.toString() : time_m)
3760							+ ':'
3761							+ (time_s<10 ? '0'+time_s.toString() : time_s);
3762
3763				_this.box.find('.jcm-refresh-sub').text (time_fm);
3764
3765				timeSub-=1;
3766			}, 1000);
3767		}
3768
3769		// extend links
3770		var __jumpToCmid=function(id){
3771			_this.box.find('.jcm-block._light').removeClass('_light');
3772			_this.box.find('.jcm-block._blue').removeClass('_blue');
3773
3774			if($('#comment-'+id).length)
3775			{
3776				let elCm=$('#comment-'+id),
3777					elCmTo=function(){
3778						$('html, body').animate({
3779					        scrollTop: elCm.offset().top-100
3780					    }, 300, function(){
3781					    	elCm.addClass('_light');
3782					    });
3783					};
3784
3785				if(settings.openform!='0'){
3786					setTimeout(function(){
3787						elCmTo();
3788					}, 1000);
3789				} else {
3790					elCmTo();
3791				}
3792
3793			    return;
3794			}
3795
3796			var _config = {
3797				timestamp : _this.timestamp.hasOwnProperty(0) ? _this.timestamp[0] : _this.config.timestamp,
3798				parent_id : 0,
3799				timestamp_offset : 0,
3800				cmid : id,
3801				unwrap : 0
3802			};
3803
3804			_this.reload(_config, function (d){
3805				_this.box.find('#jcm-comments').empty().append(d.html);
3806				
3807				$('html, body').animate({
3808			        scrollTop: _this.box.find("#comment-"+id).offset().top-100
3809			    }, 500, function(){
3810			    	_this.box.find("#comment-"+id).addClass('_light');
3811			    });
3812			});
3813		};
3814
3815		$(document).on('click', 'a[data-jcm-self=1]', function(e){
3816			e.preventDefault();
3817			var wlCmid = $(this).attr('data-cmid');
3818
3819			__jumpToCmid(wlCmid);
3820		});
3821
3822		window.setInterval(function(){
3823			var wl = $('a').filter(function(){
3824				if(typeof $(this).attr('data-jcm-self')!='undefined') return false;
3825
3826				if(/^https?\:\/\//.test($(this).attr('href')))
3827				{
3828					var wUrl = new URL($(this).attr('href'));
3829					if(/\#comment-[1-9][0-9]*$/.test(wUrl.hash) && wUrl.host==window.location.host) return true;
3830
3831					return false;
3832				} else {
3833					return /\#comment-[1-9][0-9]*$/.test($(this).attr('href'));
3834				}
3835			});
3836
3837			if(!wl.length) return;
3838
3839			var wlCid=[];
3840			wl.attr('data-jcm-self', 0);
3841			wl.each(function(){
3842				var wlAll=$(this).attr('href').match(/\#comment-([1-9][0-9]*)$/);
3843				wlCid.push(wlAll[1]*1);
3844				$(this).attr('data-cmid', wlAll[1]*1);
3845			});
3846
3847			if(!wlCid.length) return;
3848
3849			$.post(_this.helper.url({task:'item.cin'}), {cid:wlCid.join(','), key:_this.config.key}, function(d){
3850				if(d.status!=200) return;
3851				$.each(d.data, function(kj, vj){
3852					if(vj.sf==1) $('a[data-jcm-self][data-cmid='+vj.id+']').attr('data-jcm-self', 1);
3853				});
3854			}, 'json');
3855		}, 100);
3856
3857		if(/\#comment-[1-9][0-9]*$/.test(window.location.hash)){
3858			var wlAll = window.location.hash.match(/\#comment-([1-9][0-9]*)$/);
3859			__jumpToCmid(wlAll[1]*1);
3860		}
3861
3862		let urlParams = new URLSearchParams(window.location.search);
3863		let cmIdQuery = urlParams.get('comment_id');
3864		if(!settings.cache && /^[1-9][0-9]*$/.test(cmIdQuery)){
3865			__jumpToCmid(cmIdQuery*1);
3866		}
3867	};
3868
3869	this.reload = function(extend, callback, failureCb)
3870	{
3871		var _config = $.extend( true, {}, _this.config);
3872		if (typeof extend=='object')
3873		{
3874			$.each (extend, function(k,v)
3875			{
3876				_config[k] = extend[k];
3877			});
3878		}
3879
3880		delete _config.box;
3881		delete _config.request;
3882
3883		$.get(_this.helper.url({task:'items.reload'}), _config, function(d){
3884			if(typeof d!='object' || d.status==400)
3885			{
3886				if (typeof failureCb == 'function')
3887					failureCb(d);
3888				return false;
3889			}
3890
3891			// success
3892			if (typeof callback=='function')
3893				callback (d);
3894
3895			$(window).trigger('resize');
3896		},'json');
3897	};
3898
3899	this.paginationEvent = function(ctrEl, pageEl, cmList)
3900	{
3901		var _way 		= ctrEl.hasClass('_page_next') ? 'next' : 'previous',
3902			_limit 		= pageEl.attr ('data-limit') * 1,
3903			_page 		= pageEl.attr ('data-page') * 1,
3904			_total 		= pageEl.attr ('data-total') * 1,
3905			_pid 		= pageEl.attr ('data-pid') * 1,
3906			_cmCount	= cmList.children('.jcm-block').length;
3907
3908
3909		ctrEl.click(function(e){
3910			e.preventDefault();
3911
3912			if(ctrEl.hasClass('jcm-loading')) return;
3913
3914			cmList.find('>li.hide').removeClass('hide');
3915			if(ctrEl.hasClass('jshow')){
3916				ctrEl.remove();
3917				return;
3918			}
3919
3920			var _pageCurr = _cmCount/_limit > parseInt(_cmCount/_limit) ? parseInt(_cmCount/_limit)+1 : parseInt(_cmCount/_limit);
3921			var _config = {
3922					parent_id : _pid,
3923					page_comment : _way=='next' ? _page+1 : (_page-_pageCurr)
3924				};
3925
3926			ctrEl.addClass('jcm-loading');
3927
3928			_this.reload (_config,
3929				function(d){
3930					// success
3931					ctrEl.removeClass ('jcm-loading');
3932					if (_way=='next')
3933					{
3934						_page += 1;
3935						if (_page>=_total)
3936						{
3937							ctrEl.remove ();
3938						}
3939						cmList.append (d.html);
3940					} else {
3941						if (_config.page_comment == 1)
3942						{
3943							ctrEl.remove ();
3944						}
3945						cmList.prepend (d.html);
3946						_cmCount += _limit;
3947					}
3948				},
3949				function (d){
3950					// failure
3951					ctrEl.removeClass ('jcm-loading');
3952				}
3953			);
3954		});
3955	};
3956
3957	this.paginationChild = function()
3958	{
3959		// jcm-childs
3960		if(!_this.box.find('.jcm-childs').not('._page').length) return false;
3961
3962		_this.box.find('.jcm-childs').not('._page').each(function(){
3963			var _el = $(this);
3964			_el.addClass('_page');
3965
3966			if(!_el.next('.jcm-pagination-data').length)
3967				return true; // continue;
3968
3969			var _pageEl 	= _el.next('.jcm-pagination-data'),
3970				_pageTotal 	= _pageEl.attr ('data-total') * 1,
3971				_pageLimit 	= _pageEl.attr ('data-limit') * 1,
3972				_pageActive = _pageEl.attr ('data-page') * 1,
3973				lengthCm 	= _el.children ('.jcm-block').length;
3974
3975			if(_pageTotal>1 && _pageLimit*_pageActive>lengthCm)
3976			{
3977				// pagination before
3978				var _ctrEl = $('<a href="#" class="_page_previous">'+_this.lang.get('show_previous_comments')+'</a>');
3979				_el.before (_ctrEl);
3980				_this.paginationEvent (_ctrEl, _pageEl, _el);
3981			}
3982
3983			// _pageTotal>_pageActive?
3984			if(_pageTotal>_pageActive)
3985			{
3986				// pagination after
3987				var _ctrEl = $('<a href="#" class="_page_next">'+_this.lang.get('show_more_reply')+'</a>');
3988				_el.after(_ctrEl);
3989				_this.paginationEvent(_ctrEl, _pageEl, _el);
3990
3991				if((config.id<1 || (config.id>0 && !_el.find('>#comment-'+config.id).length)) && _el.find('>li').length>
3991settings.preview)
3992				{
3993					_el.find('>li').slice(settings.preview).addClass('hide');
3994				}
3995			} else {
3996				if((config.id<1 || (config.id>0 && !_el.find('>#comment-'+config.id).length)) && _el.find('>li').length>settings.preview)
3997				{
3998					// pagination after
3999					var _ctrEl = $('<a href="#" class="_page_next jshow">'+_this.lang.get('show_more_reply')+'</a>');
4000					_el.after(_ctrEl);
4001					_this.paginationEvent(_ctrEl, _pageEl, _el);
4002
4003					_el.find('>li').slice(settings.preview).addClass('hide');
4004				}
4005			}
4006		});
4007	};
4008
4009	this.paginationRoot = function()
4010	{
4011		var urlRoot = null,
4012		loadPage = function(page, cb)
4013		{
4014			var _config = {
4015				timestamp : _this.timestamp.hasOwnProperty(0) ? _this.timestamp[0] : _this.config.timestamp,
4016				parent_id : 0,
4017				timestamp_offset : 0,
4018				page_comment : page,
4019				unwrap : 0
4020			};
4021
4022			if(_this.tmpCache.hasOwnProperty(page))
4023			{
4024				_this.box.find('#jcm-comments').empty().append(_this.tmpCache[page]);
4025				_this.box.find('.jcm-root-page a').each(function(){
4026					var page = $(this).attr('data-page') * 1,
4027						newUrl = urlRoot.replace(/page_comment=[1-9][0-9]*/,'page_comment=' + page);
4028					$(this).attr('href', newUrl);
4029				});
4030				return;
4031			}
4032
4033			_this.reload(_config, function (d){
4034				_this.tmpCache[page] = d.html;
4035				_this.box.find('#jcm-comments').empty().append (d.html);
4036				
4037				if(urlRoot!=null)
4038				{
4039					_this.box.find('.jcm-root-page a').each (function(){
4040						var page = $(this).attr('data-page') * 1,
4041							newUrl = urlRoot.replace(/page_comment=[1-9][0-9]*/,'page_comment=' + page);
4042
4043						$(this).attr('href', newUrl);
4044					});
4045				}
4046
4047			    if(typeof cb=='function'){
4048			    	cb();
4049			    } else {
4050			    	$('html, body').animate({
4051				        scrollTop: $('#jcm-comments').offset().top-100
4052				    }, 300);
4053			    }
4054			});
4055		};
4056
4057		// first state
4058		if(_this.config.page_comment==1)
4059		{
4060			//window.history.pushState({etype:'jcm', page:1}, '', window.location.href);
4061
4062			// off cache
4063			if(!settings.cache)
4064			{
4065				if(config.id>0){
4066					$('#jcm-comments').removeClass('hide hidden');
4067				} else {
4068					_this.config.timestamp=parseInt(new Date().getTime()/1000);
4069
4070					loadPage(1, function(){
4071						$('#jcm-comments').removeClass('hide hidden');
4072					});
4073				}
4074			}
4075		}
4076
4077		_this.box.on('click', '.jcm-root-page a', function(e){
4078			e.preventDefault();
4079			var _el  = $(this),
4080				page = _el.attr('data-page')*1,
4081				url  = _el.attr('href');
4082
4083			if(urlRoot==null) urlRoot=url;
4084
4085			if(_el.parent().hasClass('a-selected')) return false;
4086
4087			_el.parent().siblings().removeClass('a-selected');
4088			_el.parent().addClass('a-selected');
4089
4090			loadPage(page);
4091			window.history.pushState({etype:'jcm', page:page}, '', url);
4092		});
4093
4094		window.onpopstate = function(e){
4095		    if(e.state && e.state.etype=='jcm'){
4096		        loadPage(e.state.page);
4097		    }
4098
4099		    if(e.state==null)
4100		    {
4101		    	/*loadPage (1);*/
4102		    }
4103		};
4104	};
4105
4106	this.init = function() 
4107	{
4108		if(_this.box==null || !_this.box.length)
4109		{
4110			console.log("Error: No comment box found.");
4111			return false;
4112		}
4113
4114		if(settings.hasOwnProperty('translate'))
4115		{
4116			_this.lang.load(settings.translate);
4117		}
4118
4119		if(/\#comment-[1-9][0-9]*$/.test(window.location.hash)){
4120			var wlAll = window.location.hash.match(/\#comment-([1-9][0-9]*)$/);
4121			config.id=wlAll[1]*1;
4122		}
4123
4124		let urlParams = new URLSearchParams(window.location.search);
4125		let cmIdQuery = urlParams.get('comment_id');
4126		if(!settings.cache && /^[1-9][0-9]*$/.test(cmIdQuery)){
4127			config.id=cmIdQuery*1;
4128		}
4129
4130		_this.box.on('emoji', function(){
4131			if(!_this.emoji.loaded)
4132			{
4133				_this.emoji.loaded=true;
4134				_this.emoji.init();
4135			}
4136		});
4137
4138		// adjust url
4139		var curl = window.location.href.replace(window.location.hash, '');
4140		if(curl.indexOf(settings.url)==-1)
4141		{
4142			settings.url = curl.replace(/(\?|\&)?page_comment\=[0-9]*/g,'');
4143			_this.box.find('.page-button a').each(function(){
4144				var _page = $(this).attr('data-page'),
4145					_newUrl = settings.url+(settings.url.indexOf('?')==-1?'?':'&')+'page_comment='+_page;
4146				$(this).attr('href', _newUrl);
4147			});
4148		}
4149		
4150		_this.events();
4151		_this.tpl.form = _this.box.find("#jcm-form").clone();
4152		_this.createFormEvents(_this.box.find("#jcm-form"));
4153
4154		// listen event
4155		$(window).on('jcmQuote', function(e, text){
4156			$('#jcm-form .jcm-textarea').html('<div data-tag="quote" data-area="self">'+text+'</div><div>...</div>');
4157
4158			$('#jcm-form').toggleClass('active');
4159			$('#jcm-form .jcm-textarea').focus();
4160		});
4161
4162		_this.paginationRoot();
4163
4164		// highlight comment
4165		if(config.id>0)
4166		{
4167			let fff=function(){
4168				$('html, body').animate({
4169			        scrollTop: _this.box.find("#comment-"+config.id).offset().top-100
4170			    }, 500, function(){
4171			    	_this.box.find("#comment-"+config.id).addClass('_light');
4172			    });
4173			};
4174
4175			window.setTimeout(function(){
4176				fff();
4177				$(window).on('load', function(){ fff(); });
4178			}, 2000);
4179		}
4180
4181		var hlDelay=null;
4182		$('body').click(function(e){
4183			if(hlDelay!=null) clearTimeout(hlDelay);
4184
4185			hlDelay=setTimeout(function(){
4186				if($(e.target).closest('.jcm-block').length)
4187				{
4188					var el=$(e.target).closest('.jcm-block');
4189					if(!el.hasClass('_light') && !el.hasClass('_blue'))
4190					{
4191						_this.box.find('.jcm-block').removeClass('_light _blue');
4192					}
4193				}
4194			}, 100);
4195		});
4196
4197		// fontawesome
4198		if(config.awe.v=="v4")
4199		{
4200			var aj=function(){
4201				$('#jlexcomment, .jcm-dialog').find('.far, .fas')
4202					.removeClass('far fas')
4203					.addClass('fa');
4204
4205				var ic_maps = {
4206					'fa-map-marker-alt':'fa-map-marker',
4207					'fa-grin-hearts':'fa-smile-o',
4208					'fa-arrow-alt-circle-down':'fa-arrow-circle-down'
4209				};
4210
4211				$.each(ic_maps, function(o, n){
4212					$('.'+o).removeClass(o).addClass(n);
4213				});
4214			}
4215			
4216			aj();
4217			$(document).ajaxComplete(function(){aj()});
4218		}
4219
4220		if(config.awe.src=="local" && config.awe.v=="v5")
4221		{
4222			var aj=function(){
4223				$('#jlexcomment, .jcm-dialog').find('.far')
4224					.removeClass('far')
4225					.addClass('fas');
4226			}
4227			aj();
4228			$(document).ajaxComplete(function(){aj()});
4229		}
4230	};
4231}

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.