PageSourceSearch

https://tekstaro.com/js/serchilo.js?v=518

js tekstaro.com collected 2026-10-02 07:35:29 UTC 106,806 bytes, 3,355 lines download raw bytes

1/* jshint esversion: 11 */
2/* globals console, URLSearchParams, AbortController */
3
4export const serchilo = (VERSIO, LOKE) => {
5	const CON = console.log; // POR DAŬRA UZO
6	const foliomemoro_maksimumo = 30;
7	const body = $('body');
8	const dok = $(document);
9	const URLParametroj = new URLSearchParams(window.location.search);
10	const MontriTempon = false; // Uzi logadon de la daŭro de serĉovokoj
11	let mmm = 1000;
12	const url_mmm = URLParametroj.get('mmm');
13	if (url_mmm) {
14		mmm = parseInt(url_mmm)
15	} else {
16		mmm = 1000
17	}
18	let url_id = URLParametroj.get('s');
19	if (url_id) {
20		url_id = url_id.replace(/\W/g, '');
21	}
22
23	let majuskliga_klavo = false;
24	let jhus_elektita_teksto = false;
25	let foliomemoro = [];
26	let unika_id = 1;
27	let laekjaro = 0, lafinjaro = 0;
28	let dialogo_malfermita = false;
29	let serchilo_aktiva = true;
30	let fulmoklavoj_aktivaj = false;
31
32	let programoj = {
33		'serchi': '/py/serchi.py',
34		'alineo': '/py/alineo.py',
35		'teksto': '/py/teksto.py',
36		'tutateksto': '/t',
37		'sekcio': '/s',
38		'tekstolisto': '/py/tekstolisto.py',
39		'krei_ligilon': '/py/krei_ligilon.py',
40	};
41
42	const Rulumoj = () => { return {top: dok.scrollTop(), left: dok.scrollLeft()};};
43	let rulumoj = Rulumoj();
44
45	$(document).on('keydown', evento => {
46		majuskliga_klavo = evento.shiftKey ? true:false;
47	});
48	$(document).on('keyup', evento => {
49		majuskliga_klavo = evento.shiftKey ? true:false;
50	});
51
52	const FermiDialogon = (dialogo) => {
53		dialogo.off().remove();
54		rulumoj = Rulumoj();
55		dialogo_malfermita = false;
56		setTimeout(function() {
57			body.removeClass('dialogo');
58		}, 100);
59	};
60
61	const Dialogo = (teksto, agoj, finago, tujago) => {
62		rulumoj = Rulumoj();
63		const mia_id = 'dialogo' + unika_id++;
64		const dialogo = $(`<div id="${mia_id}" class="dialogo">`);
65		const ekstera = $('<div class="ekstera" tabindex="-1">');
66		dialogo.data('ekstera', ekstera);
67		const ena = $(`<div class="ena">`);
68		const kapo = $('<header/>');
69		const h2 = $(`<h2>Tekstaro</h2>`);
70		const butono_fermi = $('<button class="fermilo fokusebla" title="Fermi">✕</button>');
71		const enhavo = $(`<div class="enhavo"/>`);
72		if (typeof teksto === 'string') {
73			enhavo.text(teksto);
74		} else {
75			enhavo.append(teksto);
76		}
77		h2.append(butono_fermi);
78		kapo.append(h2);
79
80		ena.append(kapo).append(enhavo);
81
82		let piedo;
83		if (agoj && agoj.length) {
84			piedo = $('<footer/>');
85			agoj.forEach(ago => {
86				let butono;
87				if (typeof ago === 'string') {
88					butono = $('<p class="dialogoteksto"/>').text(ago);
89				} else {
90					if (ago.hasClass && ago.hasClass('informoj')) {
91						piedo.append(ago);
92					} else {
93						butono = $('<button/>');
94						if (typeof ago.teksto === 'string') {
95							butono.text(ago.teksto);
96						} else {
97							butono.append(ago.teksto);
98						}
99						if (ago.click) {
100							butono.addClass('click').data('click', ago.click);
101						}
102					}
103				}
104				piedo.append(butono);
105			});
106			ena.append(piedo);
107		} else {
108			enhavo.addClass('senbutonoj');
109		}
110
111		ekstera.append(ena);
112		dialogo.append(ekstera);
113
114		body.append(dialogo).addClass('dialogo');
115		const window_width = $(window).width();
116		ekstera.css({'width': (window_width) + 'px'});
117
118		dialogo_malfermita = dialogo;
119
120		if (piedo) {
121			piedo.find('button').first().focus();
122		} else {
123			butono_fermi.focus();
124		}
125
126		dialogo.on('keyup', (e) => {
127			if (e.which === 27) {
128				FermiDialogon(dialogo);
129				if (finago) {
130					finago();
131				}
132			}
133		});
134		dialogo.on('click', 'button.click', (e) => {
135			const butono = $(e.currentTarget);
136			const click = butono.data('click');
137			if (typeof click === 'function') {
138				click();
139			}
140			if (finago) {
141				finago();
142			}
143			FermiDialogon(dialogo);
144		});
145		dialogo.on('click', 'button.fermilo, div.ekstera', e => {
146			FermiDialogon(dialogo);
147			if (finago) {
148				finago();
149			}
150		});
151
152		if (tujago) {
153			tujago();
154		}
155		return dialogo;
156	};
157
158
159	// UNU FOJON EN HORO KONTROLI, ĈU LA TEKSTARO HAVAS NOVAN VERSION
160	const KontroliVersion = () => {
161		setTimeout( () => {
162			fetch(
163				'/versio.txt?' + (new Date()).getTime()
164			).then(
165				respondo => {
166					if (respondo.ok) {
167						return respondo.text();
168					} else {
169						return false;
170					}
171				}
172			).then(
173				versio => {
174					if (versio) {
175						versio = parseInt(versio.trim(), 10);
176						if (versio !== VERSIO) {
177							Dialogo(
178								$(`
179									<div>
180										<p>Intertempe aperis nova versio de la Tekstaro.</p>
181										<p>Indas reŝargi la paĝon.</p>
182									</div>
183								`),
184								[
185									{
186										teksto: 'Jes, reŝargu la paĝon',
187										click: () => {
188											window.location.reload(true);
189										}
190									},
191									{
192										teksto: 'Ne, faru nenion'
193									}
194								],
195								() => {
196									VERSIO = versio;
197									KontroliVersion();
198								}
199							);
200						} else {
201							KontroliVersion();
202						}
203					} else {
204						CON('Kontroleraro', versio);
205					}
206				}
207			).catch(
208				eraro => {
209					CON('Kontroleraro:', eraro);
210				}
211			);
212		}, (60000 * 60));
213	};
214
215	const URLKodi = t => {
216		if (t === null || t === undefined) {
217			return '';
218		}
219		return encodeURIComponent(t);
220	};
221
222	const KreiMendon = para => Object.keys(para).map(key => URLKodi(key) + '=' + URLKodi(para[key])).join('&');
223
224	const GhustigiDialogon = (dialogo) => dialogo.data('ekstera').css({width: $(document).width() + 'px'});
225
226	$(window).on('resize', () => {
227		if (dialogo_malfermita) {
228			GhustigiDialogon(dialogo_malfermita);
229		}
230	});
231
232	const serchilo = $('#serchilo');
233	const jaroj = $('#jaroj');
234	const jarojaktivaj = $('#jarojaktivaj');
235	const ekjaro = $('#ekjaro');
236	const finjaro = $('#finjaro');
237	const restarigi_foliojn = $('#restarigi_foliojn');
238	const restarigi_foliojn_select = $('#restarigi_foliojn_select');
239	const serchilolangeto = $('#serchilolangeto');
240	const serchilolangetoli = $('#serchilolangetoli');
241	serchilolangetoli.data('folio', serchilo);
242	const tekstoj = $('#tekstoj');
243	const grandeco = $('#grandeco').find('strong');
244	const vortosumo_elektitaj_tekstoj = $('#vortosumo_elektitaj_tekstoj')
245	const serchesprimoj = $('#serchesprimoj');
246	const serchesprimo1 = $('#serchesprimo1');
247	const iloj = $('#iloj');
248	const largho = $('#largho');
249	const maksimumo = $('#maksimumo');
250	const ignorifremdajhojn = $('#ignorifremdajhojn');
251	const ignorimallongigojn = $('#ignorimallongigojn');
252	const uskle = $('#uskle');
253	const inverse = $('#inverse');
254	const rapide = $('#rapide');
255	const daurigi = $('#daurigi');
256	const kunigitekstojn = $('#kunigitekstojn');
257	const uzistreketojn = $('#uzistreketojn');
258	const kunigiserchojn = $('#kunigiserchojn');
259	const chiuj = $('#chiuj');
260	const neniuj = $('#neniuj');
261	const inversigi = $('#inversigi');
262	const zamenhofaj = $('#zamenhofaj');
263	const montriinformojn = $('#montriinformojn');
264	const shalti = $('#shalti');
265	const pivautoroj = $('#pivautoroj');
266	const aldoniserchesprimon = $('#aldoniserchesprimon');
267	const forigiserchesprimon = $('#forigiserchesprimon');
268	const serchesprimtitolo = $('#serchesprimtitolo');
269	const formularo = $('#formularo');
270	const la_butonoj = $('#butonoj');
271	const priserchi = $('#priserchi');
272	const fermichiujn = $('#fermichiujn');
273	const haltigichiujn = $('#haltigichiujn');
274	const fulmoklavoj = $('#fulmoklavoj');
275	let chiuj_tekstoj;
276	let stato;
277	try {
278		stato = JSON.parse(localStorage.getItem('stato'));
279	} catch(e) {
280		CON('ERARO stato', e);
281	}
282	if (!stato) {
283		stato = {};
284	}
285	if (stato.fulmoklavoj === 1 && !fulmoklavoj.prop('checked')) {
286		fulmoklavoj.trigger('click');
287	}
288	if (stato.maksimumo && stato.maksimumo > mmm) {
289		stato.maksimumo = mmm
290	}
291	const memorataj_serchesprimoj = [];
292
293	let folioj, langetoj, foliojene, tekstoadapto, jamkonservas = false, serchesprimonumero = 1, langetonumero = 0;
294
295	const Objektigi = obj => (!obj || ( $.isArray(obj) && ! obj.length)) ? {} : obj;
296
297	const FariSerchon = (para, folio) => {
298		if (para.rapide) {
299			let akumulo = {trafoj: 0, plenumitaj_serchoj: 0};
300			let n = -1;
301			while (n <= para.elektitaj_tekstoj.length - 2) {
302				n += 1;
303				Serchi(para, folio, n, akumulo);
304			}
305		} else {
306			Serchi(para, folio, 0);
307		}
308	};
309
310	const ForigiTekstelekton = () => {
311		const sel = window.getSelection ? window.getSelection() : document.selection;
312		if (sel) {
313			if (sel.removeAllRanges) {
314				sel.removeAllRanges();
315			} else if (sel.empty) {
316				sel.empty();
317			}
318		}
319	};
320
321	const MarkiElektilojn = (parametroj) => {
322		let daurigi_label = daurigi.closest('span.ilojlabel');
323		daurigi_label.toggleClass('neebla', !!parametroj.rapide && !parametroj.kunigitekstojn);
324		let rapide_label = rapide.closest('span.ilojlabel');
325		rapide_label.toggleClass('neebla', !!parametroj.kunigitekstojn);
326	};
327
328	const PreniSerchilostaton = chiam => {
329		const parametroj = {};
330		parametroj.serchesprimoj = [];
331		serchesprimoj.find('input').each( (index, input) => {
332			input = $(input);
333			const valoro = input.val().replace(/ {2,}/g, ' ');
334			input.val(valoro);
335			if (valoro !== '') {
336				parametroj.serchesprimoj.push(valoro);
337			}
338		});
339		if (!chiam && !parametroj.serchesprimoj.length) {
340			return -1;
341		}
342
343		parametroj.elektitaj_tekstoj = [];
344		var elektitaj_tekstoj = tekstoj.find('div.teksto.elektita').toArray()//.reverse()
345		if (inverse.prop('checked')) {
346			elektitaj_tekstoj = elektitaj_tekstoj.reverse()
347		}
348		elektitaj_tekstoj.forEach( (div, index) => {
349			div = $(div);
350			const data = div.data('data');
351			const {nomo} = data;
352			if (nomo) {
353				parametroj.elektitaj_tekstoj.push(nomo);
354			}
355		});
356		if (parametroj.elektitaj_tekstoj.length === chiuj_tekstoj.length) {
357			parametroj.chiuj = 1;
358		} else {
359			parametroj.chiuj = 0;
360		}
361
362		if (!chiam && !parametroj.elektitaj_tekstoj.length) {
363			return -2;
364		}
365		parametroj.malshaltitaj_tekstoj = [];
366		tekstoj.find('div.teksto.malshaltita').each( (index, div) => {
367			div = $(div);
368			const data = div.data('data');
369			const {nomo} = data;
370			if (nomo) {
371				parametroj.malshaltitaj_tekstoj.push(nomo);
372			}
373		});
374		if (parametroj.malshaltitaj_tekstoj.length || parametroj.elektitaj_tekstoj.length) {
375			shalti.removeClass('kashita');
376		} else {
377			shalti.addClass('kashita');
378		}
379		parametroj.largho = parseInt(largho.val(),10);
380		parametroj.maksimumo = parseInt(maksimumo.val(),10);
381		parametroj.uskle = uskle.prop('checked') ? 1 : 0;
382		parametroj.ignorifremdajhojn = ignorifremdajhojn.prop('checked') ? 1 : 0;
383		parametroj.ignorimallongigojn = ignorimallongigojn.prop('checked') ? 1 : 0;
384		parametroj.daurigi = daurigi.prop('checked') ? 1 : 0;
385		parametroj.kunigitekstojn = kunigitekstojn.prop('checked') ? 1 : 0;
386		parametroj.uzistreketojn = uzistreketojn.prop('checked') ? 1 : 0;
387		parametroj.kunigiserchojn = kunigiserchojn.prop('checked') ? 1 : 0;
388		parametroj.inverse = inverse.prop('checked') ? 1 : 0;
389		parametroj.rapide = rapide.prop('checked') ? 1 : 0;
390		parametroj.jamajtrafoj = 0;
391
392		const serchesprimospanoj = [];
393		iloj.find('span.serchesprimospan').each( (index, span) => {
394			serchesprimospanoj.push($(span).css('width'));
395		});
396		if (serchesprimospanoj.length) {
397			parametroj.serchesprimospanoj = serchesprimospanoj;
398		}
399		parametroj.jarojaktivaj = jarojaktivaj.prop('checked');
400		parametroj.ekjaro = ekjaro.val();
401		parametroj.finjaro = finjaro.val();
402		MarkiElektilojn(parametroj)
403		return parametroj;
404	};
405
406	const KolektiMarkoDatumojn = (folio, parametroj) => {
407		const markitaj = folio.find('div.trafolinio input.trafohoko:checked');
408		const nemarkitaj = folio.find('div.trafolinio input.trafohoko:not(:checked)');
409		if (markitaj.length) {
410			const alineoidoj = [];
411			if (markitaj.length < nemarkitaj.length) {
412				markitaj.each( (index, input) => {
413					const alineoid = $(input).data('alineo-id');
414					if (alineoid) {
415						alineoidoj.push(alineoid);
416					}
417				});
418				parametroj.markitaj = alineoidoj;
419			} else {
420				nemarkitaj.each( (index, input) => {
421					const alineoid = $(input).data('alineo-id');
422					if (alineoid) {
423						alineoidoj.push(alineoid);
424					}
425				});
426				parametroj.nemarkitaj = alineoidoj;
427			}
428		}
429		if (folio.hasClass('kashimarkitajn')) {
430			parametroj.kashimarkitajn = 1;
431			parametroj.kashinemarkitajn = 0;
432		} else if (folio.hasClass('kashinemarkitajn')) {
433			parametroj.kashinemarkitajn = 1;
434			parametroj.kashimarkitajn = 0;
435		}
436	};
437
438	const KonserviSerchilostaton = () => {
439		if (jamkonservas) {
440			return;
441		}
442		jamkonservas = true;
443		const parametroj = PreniSerchilostaton(true);
444		const paramemoroj = [];
445		foliojene.find('div.folio:not(.forigita)').each( (index, folio) => {
446			folio = $(folio);
447			const shanghi = folio.data('shanghi');
448			if (shanghi) {
449				const paramemoro = shanghi.data('paramemoro');
450				if (paramemoro) {
451					paramemoro.teksto = folio.data('langeto').find('code').text();
452					KolektiMarkoDatumojn(folio, paramemoro);
453					paramemoroj.unshift(paramemoro);
454				}
455			}
456		});
457		parametroj.fulmoklavoj = fulmoklavoj.prop('checked') ? 1 : 0
458		if (paramemoroj.length) {
459			while (paramemoroj.length > foliomemoro_maksimumo) {
460				paramemoroj.shift();
461			}
462			parametroj.paramemoroj = paramemoroj;
463		}
464		try {
465			localStorage.setItem('stato', JSON.stringify(parametroj));
466		}
467		catch(e) {
468			CON('konservaderaro', e);
469		}
470
471		jamkonservas = false;
472	};
473
474	const AdaptiSerchesprimtitolon = pliaj => {
475		if (pliaj) {
476			serchesprimtitolo.text('Serĉesprimoj');
477		} else {
478			const nombro = serchesprimoj.find('input').length;
479			if (nombro === 1) {
480				serchesprimtitolo.text('Serĉesprimo');
481				forigiserchesprimon.removeClass('aktiva');
482			} else {
483				serchesprimtitolo.text('Serĉesprimoj');
484			}
485		}
486	};
487
488	const IgiRegrandigebla = loko => {
489		var r = loko.find('.regrandigebla').each( function() {
490			var tenilo = $(this).find('span.tenilo');
491			if (tenilo.length) {
492				tenilo.text('');
493				var input = $(this).find('input');
494				if (input.length) {
495					tenilo.height(input.outerHeight() + 'px');
496				}
497			}
498		});
499		r.removeClass('regrandigebla').resizable(
500			{
501				'handleSelector': '>span.tenilo',
502				'resizeHeight': false,
503				'onDragEnd': () => KonserviSerchilostaton(true)
504			}
505		);
506	};
507
508	const AldoniSerchesprimon = (serchesprimo, fokusi) => {
509		const span = $('<span class="serchesprimospan plia regrandigebla">');
510		const input = serchesprimo1.clone(true);
511		const numero = ++serchesprimonumero;
512		span.prop('id', 'serchesprimospan' + numero);
513		input.prop('id', 'serchesprimo' + numero);
514		input.data('numero', numero);
515		input.addClass('plia');
516		if (serchesprimo !== null) {
517			input.val(serchesprimo);
518		} else {
519			if (memorataj_serchesprimoj.length) {
520				input.val(memorataj_serchesprimoj.pop());
521			} else {
522				input.val('');
523			}
524		}
525		const fermilo = $('<img src="bildoj/x16.gif" class="serchesprimfermilo" title="Fermi la serĉesprimon">').data('span', span);
526		const tenilo = $('<span class="tenilo"></span>');
527		span.append(input).append(fermilo).data('input', input).data('fermilo', fermilo);
528		span.append(tenilo);
529		serchesprimoj.append(span);
530		IgiRegrandigebla(serchesprimoj);
531		forigiserchesprimon.addClass('aktiva');
532		AdaptiSerchesprimtitolon(true);
533		if (fokusi) {
534			input.focus();
535		}
536	};
537	aldoniserchesprimon.on('click', () => AldoniSerchesprimon(null, true));
538
539	const PrilaboriFoliomemoron = () => {
540		while (foliomemoro.length > foliomemoro_maksimumo) {
541			const forigota = foliomemoro.shift();
542			if (forigota && forigota.langeto) {
543				forigota.langeto.remove();
544				forigota.folio.remove();
545			}
546		}
547		if (foliomemoro.length) {
548			restarigi_foliojn_select.html('');
549			let option;
550			foliomemoro.slice().reverse().forEach(mem => {
551				option = $('<option class="remetota">');
552				let text;
553				if (mem.langeto) {
554					text = mem.langeto.find('code').text();
555				} else if (mem.teksto) {
556					text = mem.teksto;
557				}
558				if (text) {
559					option.text(text);
560					option.data('remetota', mem);
561					restarigi_foliojn_select.append(option);
562				}
563			});
564			option = $('<option class="malplena" disabled selected hidden>');
565			if (foliomemoro.length > 0) {
566				option.text('bv. elekti...');
567			}
568			restarigi_foliojn_select.prepend(option);
569			if (foliomemoro.length > 1) {
570				option = $('<option class="chiujn">').text('Restarigi ĉiujn');
571				restarigi_foliojn_select.append(option);
572			}
573			restarigi_foliojn.removeClass('kashita');
574		} else {
575			restarigi_foliojn.addClass('kashita');
576		}
577		restarigi_foliojn_select.prop('selectedIndex', 0);
578	};
579
580	const PrezentiNombron = n => {
581		return n.toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1.');
582	};
583
584	const RekalkuliTekstokvanton = () => {
585		const elektitaj = tekstoj.find('div.teksto.elektita');
586		let sumo = 0;
587		elektitaj.each( (index, el) => {
588			const data = $(el).data('data');
589			sumo += parseInt(data.grandosen, 10) || 0;
590		});
591		const rx = /(\d)(\d\d\d)\b/;
592		let sumoprezento = PrezentiNombron(sumo.toString(10));
593		if (sumo > 999999) {
594			sumoprezento += ' da vortoj';
595		} else {
596			sumoprezento += ' vortoj';
597		}
598		grandeco.text(sumoprezento).data('sumo', sumo);
599		if (elektitaj.length === 0) {
600			vortosumo_elektitaj_tekstoj.text('')
601		} else if (elektitaj.length === 1) {
602			vortosumo_elektitaj_tekstoj.text(' de la elektita teksto')
603		} else {
604			vortosumo_elektitaj_tekstoj.text(' de la ' + elektitaj.length + ' elektitaj tekstoj')
605		}
606	};
607
608	const ReghustigiSerchesprimojn = () => {
609		const serchilolargho = (serchilo.width() - 30);
610		iloj.find('span.serchesprimospan').each(
611			(index, span) => {
612				span = $(span);
613				let width = span.css('width');
614				if (parseFloat(width) > serchilolargho) {
615					width = serchilolargho + 'px';
616				}
617				span.css({'width': width});
618			}
619		);
620	};
621
622	const RestarigiSerchilostaton = parametroj => {
623		if (!parametroj.ekjaro || parametroj.ekjaro === 0) {
624			parametroj.ekjaro = '';
625		}
626		if (!parametroj.finjaro || parametroj.finjaro === 0) {
627			parametroj.finjaro = '';
628		}
629		ekjaro.val(parametroj.ekjaro);
630		finjaro.val(parametroj.finjaro);
631
632		ekjaro.data('min', laekjaro);
633		if (parametroj.finjaro) {
634			ekjaro.data('max', parametroj.finjaro);
635		} else {
636			ekjaro.data('max', lafinjaro);
637		}
638
639		if (parametroj.ekjaro) {
640			finjaro.data('min', parametroj.ekjaro);
641		} else {
642			finjaro.data('min', laekjaro);
643		}
644		finjaro.data('max', lafinjaro);
645
646		parametroj.jarojaktivaj = !!parametroj.jarojaktivaj;
647		jarojaktivaj.prop('checked', parametroj.jarojaktivaj);
648		jaroj.toggleClass('aktiva', parametroj.jarojaktivaj);
649		body.toggleClass('jaroj', parametroj.jarojaktivaj);
650		la_butonoj.toggleClass('jaroj', parametroj.jarojaktivaj);
651		if (!parametroj.jarojaktivaj) {
652			ekjaro.prop('disabled', true);
653			finjaro.prop('disabled', true);
654		}
655
656		serchesprimoj.find('span.serchesprimospan.plia').remove();
657		if (parametroj.serchesprimoj) {
658			if (parametroj.serchesprimoj.length > 0) {
659				serchesprimo1.val(parametroj.serchesprimoj[0]);
660			}
661			if (parametroj.serchesprimoj.length > 1) {
662				parametroj.serchesprimoj.forEach((serchesprimo, indekso) => {
663					if (indekso > 0) {
664						AldoniSerchesprimon(serchesprimo);
665					}
666				});
667			}
668		}
669
670		if (parametroj.chiuj) {
671			tekstoj.find('div.teksto').addClass('elektita').find('input[type=checkbox]').prop('checked', true);
672		} else {
673			tekstoj.find('div.teksto').removeClass('elektita').find('input[type=checkbox]').prop('checked', false);
674			if (parametroj.elektitaj_tekstoj && parametroj.elektitaj_tekstoj.length) {
675				parametroj.elektitaj_tekstoj.forEach(teksto => $('#teksto_' + teksto).addClass('elektita').find('input[type=checkbox]').prop('checked', true));
676			}
677		}
678		if (parametroj.malshaltitaj_tekstoj && parametroj.malshaltitaj_tekstoj.length) {
679			parametroj.malshaltitaj_tekstoj.forEach(teksto => {
680				const div_teksto = $('#teksto_' + teksto);
681				div_teksto.addClass('malshaltita').find('input[type=checkbox]').prop('checked', false).find('');
682				const m = div_teksto.find('div.montri');
683				let title = m.prop('title');
684				title = title.replace(/Montri\/malŝalti/, 'Montri/reŝalti');
685				m.prop('title', title);
686			});
687		}
688		if (parametroj.elektitaj_tekstoj && parametroj.elektitaj_tekstoj.length || parametroj.malshaltitaj_tekstoj && parametroj.malshaltitaj_tekstoj.length) {
689			shalti.removeClass('kashita');
690		}
691		largho.val(parametroj.largho || 100);
692		maksimumo.val(parametroj.maksimumo || 100);
693		uskle.prop('checked', parametroj.uskle === 1 ? true : false);
694		daurigi.prop('checked', parametroj.daurigi === 1 ? true : false);
695		kunigitekstojn.prop('checked', parametroj.kunigitekstojn === 1 ? true : false);
696		uzistreketojn.prop('checked', parametroj.uzistreketojn === 1 ? true : false);
697		kunigiserchojn.prop('checked', parametroj.kunigiserchojn === 1 ? true : false);
698		inverse.prop('checked', parametroj.inverse === 1 ? true : false);
699		rapide.prop('checked', parametroj.rapide === 1 ? true : false);
700		ignorifremdajhojn.prop('checked', parametroj.ignorifremdajhojn === 1 ? true : false);
701		ignorimallongigojn.prop('checked', parametroj.ignorimallongigojn === 1 ? true : false);
702		iloj.find('input[type=checkbox]').trigger('change');
703		RekalkuliTekstokvanton();
704		if (parametroj.serchesprimospanoj && parametroj.serchesprimospanoj.length) {
705			iloj.find('span.serchesprimospan').each(
706				(index, span) => {
707					const width = parametroj.serchesprimospanoj.shift();
708					$(span).css({'width': width});
709				}
710			);
711		}
712
713		if (parametroj.paramemoroj && parametroj.paramemoroj.length) {
714			foliomemoro = parametroj.paramemoroj;
715			PrilaboriFoliomemoron();
716		}
717	};
718
719	const AktivigiSerchilon = parametroj => {
720		serchilolangeto.trigger('click');
721		if (parametroj) {
722			RestarigiSerchilostaton(parametroj);
723			KonserviSerchilostaton();
724		}
725		serchilo_aktiva = true
726	};
727
728	const AktivigiSerchofolion = serchofolio => {
729		const langeto = serchofolio.data('langeto');
730		langeto.data('scrollTop', 0);
731		langeto.find('a').trigger('click');
732		serchilo_aktiva = false
733	};
734
735	const MontriTekston = (speco, data) => {
736		let adreso, preniprogramo;
737		adreso = programoj.tutateksto + "?nomo=" + data.nomo;
738		if (speco === 'xml') {
739			adreso += "&tipo=xml";
740		}
741		if (uzistreketojn.prop('checked')) {
742			adreso += "&uzistreketojn=1";
743		}
744		window.open(adreso);
745	};
746
747	const KashiShvebinformojn = () => {
748		body.find('div.shvebinformoj').addClass('kashita');
749	};
750
751	const KomutiTekston = obj => {
752		const div = obj.closest('div.teksto');
753		let title = obj.prop('title');
754		KashiShvebinformojn();
755		if (div.hasClass('malshaltita')) {
756			div.removeClass('malshaltita');
757			title = title.replace(/Montri\/reŝalti/, 'Montri/malŝalti');
758		} else {
759			div.removeClass('elektita').find('input').prop('checked', false);
760			div.addClass('malshaltita');
761			title = title.replace(/Montri\/malŝalti/, 'Montri/reŝalti');
762		}
763		obj.prop('title', title);
764		RekalkuliTekstokvanton();
765		KonserviSerchilostaton();
766	};
767
768	const MarkiLangetonKielAktivan = (langeto, shalti) => {
769		if (shalti) {
770			langeto.addClass('serchas');
771			langeto.data('serchas', setInterval( () => langeto.toggleClass('serchas2'), 500));
772		} else {
773			let intervalo = langeto.data('serchas');
774			if (intervalo) {
775				clearInterval(intervalo);
776			}
777			langeto.removeClass('serchas').removeClass('serchas2');
778		}
779	};
780
781	const AdaptiTutanTekston = (div_tutateksto, butonodiv) => {
782		if (!butonodiv) {
783			butonodiv = div_tutateksto.closest('div.folio').find('div.butonodiv');
784		}
785		if (butonodiv.length) {
786			div_tutateksto.css({height: (window.innerHeight - (langetoj.outerHeight(true) + butonodiv.outerHeight(true))-10) + 'px'});
787		}
788	};
789
790	const AdaptiTutanSerchon = (folio) => {
791		const mdiv = folio.data('mdiv');
792		const serchorezulto = folio.data('serchorezulto');
793		serchorezulto.css({height: (window.innerHeight - (langetoj.outerHeight(true) + mdiv.outerHeight(true))-12) + 'px'});
794	};
795
796	const AdaptiChiujnTekstojn = () => {
797		langetoj.find('li.aktiva').each( (index, li) => {
798			const folio = $(li).data('folio');
799			if (folio && folio.length) {
800				if (folio.prop('id') === 'serchilo') {
801				} else if (folio.hasClass('teksto')) {
802					const butonodiv = folio.find('div.butonodiv');
803					const div_tutateksto = folio.find('div.tutateksto');
804					if (butonodiv.length && div_tutateksto.length) {
805						AdaptiTutanTekston(div_tutateksto, butonodiv);
806					}
807				} else {
808					AdaptiTutanSerchon(folio);
809				}
810			}
811		});
812		ReghustigiSerchesprimojn();
813	};
814
815	const GhustigiNombranValoron = (obj, min, maks, defaulto) => {
816		let val = obj.val().replace(/\D/g, '');
817		if (val === '') {
818			val = defaulto;
819		} else if (min !== false && val < min) {
820			val = min;
821		} else if (maks !== false && val > maks) {
822			val = maks;
823		}
824		obj.val(val);
825	};
826
827	const KreiTekstofolion = (serchofolio, trafoparametroj) => {
828		const serchofolio_id = serchofolio.prop('id');
829		const jamaj_tekstolangetoj = langetoj.find('li.langeto.teksto.' + serchofolio_id);
830		let reuzenda_langeto;
831		if (jamaj_tekstolangetoj.length) {
832			jamaj_tekstolangetoj.each( (index, l) => {
833				l = $(l);
834				const l_trafoparametroj = l.data('trafoparametroj');
835				if (l_trafoparametroj.nomo === trafoparametroj.nomo) {
836					 reuzenda_langeto = l;
837				}
838			});
839		}
840
841		let trafalineoklaso, nova_trafalineoklaso;
842		if (reuzenda_langeto) {
843			trafalineoklaso = reuzenda_langeto.data('trafalineoklaso');
844			nova_trafalineoklaso = 'trafalineo' + trafoparametroj.id;
845			reuzenda_langeto.removeClass(trafalineoklaso).addClass(nova_trafalineoklaso).data('trafalineoklaso', nova_trafalineoklaso).find('a').trigger('click');
846			return reuzenda_langeto.data('folio');
847		}
848
849		const la_titolo = $('#teksto_' + trafoparametroj.nomo).data('data').titolo;
850		const numero = ++langetonumero;
851		trafalineoklaso = 'trafalineo' + trafoparametroj.id;
852		const tekstolangeto = $('<li class="langeto teksto">').addClass(trafalineoklaso).data('trafalineoklaso', trafalineoklaso);
853		tekstolangeto.data('trafoparametroj', trafoparametroj);
854		const fermilo = $('<span class="fermilo" title="Fermi la tekston">×</span>');
855		const langeto_code = $('<code class="tekstolangeto">').text(la_titolo);
856		const langeto_a = $('<a href="#teksto' + numero + '">').prop('title', la_titolo).append(langeto_code);
857		tekstolangeto.append(langeto_a).append(fermilo);
858		const tekstofolioid = 'teksto' + numero;
859		const tekstofolio = $('<div id="' + tekstofolioid + '" class="folio teksto">');
860		tekstolangeto.addClass(serchofolio_id);
861		tekstolangeto.data('folio', tekstofolio);
862		tekstofolio.data('langeto', tekstolangeto);
863		if (jamaj_tekstolangetoj.length) {
864			jamaj_tekstolangetoj.last().after(tekstolangeto);
865		} else {
866			serchofolio.data('langeto').after(tekstolangeto);
867		}
868		tekstofolio.data('serchofolio', serchofolio);
869		foliojene.append(tekstofolio);
870
871		langeto_a.trigger('click');
872		serchilo_aktiva = false
873		return tekstofolio;
874	};
875
876	const EventualeFermiSerchesprimon = span => {
877		const input = span.data('input');
878		const valoro = input.val().trim();
879		if (valoro === '') {
880			span.remove();
881			AdaptiSerchesprimtitolon(false);
882			KonserviSerchilostaton();
883		} else {
884			input.addClass('fermota');
885			Dialogo(
886				'Ĉu fermi la markitan serĉesprimon?',
887				[
888					{
889						teksto: 'Jes, fermu ĝin',
890						click: () => {
891							memorataj_serchesprimoj.push(valoro);
892							span.remove();
893							AdaptiSerchesprimtitolon(false);
894							KonserviSerchilostaton();
895						}
896					},
897					{
898						teksto: 'Ne, lasu ĝin',
899						click: () => input.removeClass('fermota')
900					}
901				],
902				() => input.removeClass('fermota')
903			);
904		}
905	};
906
907	const RulumiAlTrafo = (tekstofolio, aldoniidon, div_tutateksto) => {
908		if (!div_tutateksto) {
909			div_tutateksto = tekstofolio.find('div.tutateksto');
910		}
911		if (div_tutateksto.length) {
912			const span_trafo = div_tutateksto.find('span.trafo');
913			if (span_trafo.length) {
914				div_tutateksto.scrollTop(0);
915				const poz = span_trafo.offset();
916				if (poz) {
917					div_tutateksto.scrollTop(poz.top-80);
918				}
919				if (aldoniidon) {
920					span_trafo.closest('*[id]').addClass('trafop');
921				}
922			}
923		}
924		return div_tutateksto;
925	};
926
927	const ElektuJare = (ek, fin) => {
928		chiuj_tekstoj.each( (index, t) => {
929			t = $(t);
930			if (!t.hasClass('malshaltita')) {
931				const jaro = parseInt(t.data('jaro'), 10);
932				if (jaro >= ek && jaro <= fin) {
933					t.addClass('elektita').find('input[type=checkbox]').prop('checked', true);
934				} else {
935					t.removeClass('elektita').find('input').prop('checked', false);
936				}
937				RekalkuliTekstokvanton();
938				KonserviSerchilostaton();
939			}
940		});
941	};
942
943	const InformoLinio = (titolo, teksto) => {
944		const span = $('<span class="informlinio"/>');
945		const strong = $('<strong/>').text(titolo + ':');
946		const em = $('<em/>').text(teksto);
947		span.append(strong).append(document.createTextNode('\u00a0')).append(em);
948		return span;
949	};
950
951	folioj = $('#folioj');
952	foliojene = folioj.find('#foliojene');
953	langetoj = folioj.find('#langetoj');
954
955	// Se dialogo estas malfermita, ne estu eble fokusi ion en la resto de la paĝo
956	folioj.on('focus', 'button, input, a', () => {
957		if (dialogo_malfermita) {
958			dialogo_malfermita.find('.fokusebla').first().focus();
959			window.scroll(rulumoj);
960		}
961	});
962
963	const KreiInformon = teksto_div => {
964		let timeout = teksto_div.data('informoj_timeout');
965		if (timeout) {
966			clearTimeout(timeout);
967		}
968		if (!tekstoj.hasClass('montriinformojn')) {
969			let montrota;
970			if (teksto_div.data('informoj')) {
971				montrota = teksto_div.data('informoj');
972				montrota.removeClass('kashita');
973				teksto_div.addClass('montrasinformojn');
974			} else {
975				montrota = $('<div class="shvebinformoj"/>');
976				teksto_div.find('span.informoj').clone().appendTo(montrota);
977				const pos = teksto_div.offset();
978				montrota.css({'top': (pos.top + 35) + 'px', 'left': (pos.left + 0) + 'px'});
979				teksto_div.data('informoj', montrota);
980				KashiShvebinformojn();
981				body.append(montrota);
982				teksto_div.addClass('montrasinformojn');
983			}
984		}
985	};
986
987	body.on('click', 'div.shvebinformoj', ({currentTarget}) => {
988		$(currentTarget).addClass('kashita');
989		body.find('div.teksto.montrasinformojn').removeClass('montrasinformojn');
990	});
991
992	tekstoj.on('mouseleave', 'div.teksto div.nomo', ({currentTarget}) => {
993		const teksto_div = $(currentTarget);
994		const montrota = teksto_div.data('informoj');
995		if (montrota) {
996			montrota.addClass('kashita');
997			teksto_div.removeClass('montrasinformojn');
998		}
999		let timeout = teksto_div.data('informoj_timeout');
1000		if (timeout) {
1001			teksto_div.data('informoj_timeout', 0);
1002			clearTimeout(timeout);
1003		}
1004	});
1005
1006	const FermiFolion = (langeto, folio, jamaj_tekstolangetoj) => {
1007		folio.find('button.finiserchon').trigger('click');
1008		let aktiva = langeto.hasClass('aktiva');
1009		MarkiLangetonKielAktivan(langeto, false);
1010		let serchofolio, la_tekstoj, memorota;
1011		let prev
1012		if (folio.hasClass('teksto')) {
1013			serchofolio = folio.data('serchofolio');
1014			langeto.remove();
1015			folio.remove();
1016		} else {
1017			prev = langeto.prev('li:not(.forigita)')
1018			const memorota_langeto = langeto.addClass('forigita');
1019			const memorota_folio = folio.addClass('forigita');
1020			memorota = {
1021				langeto: memorota_langeto,
1022				folio: memorota_folio
1023			};
1024			if (jamaj_tekstolangetoj && jamaj_tekstolangetoj.length) {
1025				la_tekstoj = [];
1026				jamaj_tekstolangetoj.each( (index, tekstolangeto) => {
1027					tekstolangeto = $(tekstolangeto);
1028					const aktiva = tekstolangeto.hasClass('aktiva');
1029					const tekstofolio = tekstolangeto.data('folio');
1030					const memorota_tekstolangeto = tekstolangeto.addClass('forigita');
1031					const memorota_tekstofolio = tekstofolio.addClass('forigita');
1032					const memorota_teksto = {
1033						langeto: memorota_tekstolangeto,
1034						folio: memorota_tekstofolio
1035					};
1036					la_tekstoj.push(memorota_teksto);
1037					if (aktiva) {
1038						AktivigiSerchilon();
1039					}
1040				});
1041				if (la_tekstoj && la_tekstoj.length) {
1042					memorota.tekstoj = la_tekstoj;
1043				}
1044			}
1045			foliomemoro.push(memorota);
1046			PrilaboriFoliomemoron();
1047			KonserviSerchilostaton();
1048		}
1049		if (aktiva) {
1050			if (serchofolio && serchofolio.length && serchofolio[0].parentNode) {
1051				AktivigiSerchofolion(serchofolio);
1052			} else {
1053				if (prev && prev.length) {
1054					prev.trigger('click')
1055				} else {
1056					AktivigiSerchilon()
1057				}
1058			}
1059		}
1060	};
1061
1062	const KreiSerchofolion = parametroj => {
1063		const numero = ++langetonumero;
1064		const langeto = $(`<li class="langeto" data-numero="${numero}">`);
1065		if (parametroj.rapide) {
1066			langeto.addClass('rapide');
1067		}
1068		let la_titolo = parametroj.serchesprimo;
1069		let jamaj_titoloj = 0;
1070		let en_ordo = true;
1071		langetoj.find('code').each( (index, code) => {
1072			const titolo = $(code).text();
1073			let rx;
1074			try {
1075				rx = new RegExp(`^(\\(\\d+\\) )?${la_titolo}$`);
1076			} catch(e) {
1077				en_ordo = false;
1078			}
1079			if (en_ordo && titolo.match(rx)) {
1080				jamaj_titoloj++;
1081			}
1082		});
1083		if (jamaj_titoloj) {
1084			la_titolo = `(${jamaj_titoloj + 1}) ${la_titolo}`;
1085		}
1086		const langeto_code = $('<code class="serchesprimolangeto">').text(la_titolo);
1087		const langeto_a = $(`<a href="#sercho${numero}">`).append(langeto_code);
1088		const fermilo = $('<span class="fermilo" title="Fermi tiun ĉi serĉofolion">×</span>');
1089		langeto.append(langeto_a).append(fermilo);
1090		const folio = $(`<div id="sercho${numero}" class="folio kashita">`);
1091		const mdiv = $('<div class="mdiv">');
1092		const kashaverto = $('<span class="kashaverto">');
1093		folio.data('kashaverto', kashaverto);
1094		const kashimarkitajn = $('<span class="kashimarkitajn butono">').text('Kaŝi markitajn').data('folio', folio);
1095		const kashinemarkitajn = $('<span class="kashinemarkitajn butono">').text('Kaŝi nemarkitajn').data('folio', folio);
1096		const malkashikashitajn = $('<span class="malkashikashitajn butono">').text('Malkaŝi kaŝitajn').data('folio', folio);
1097		const forigimarkojn = $('<span class="forigimarkojn butono">').text('Forigi markojn').data('folio', folio);
1098		mdiv.append(malkashikashitajn).append(kashimarkitajn).append(kashinemarkitajn).append(forigimarkojn).append(kashaverto);
1099		const serchorezulto = $('<div class="serchorezulto"/>');
1100		folio.data('serchorezulto', serchorezulto);
1101		folio.data('mdiv', mdiv);
1102		langeto.data('folio', folio);
1103		folio.data('langeto', langeto);
1104		const raportujo = $('<div class="raportujo">');
1105		const titolo = $('<h1>').text('Rezulto de priserĉo de la Tekstaro de Esperanto');
1106		raportujo.append(titolo);
1107		const p = $('<p class="serchoparametroj">');
1108		const serchoparatitolo = $('<strong class="serchoparatitolo">Serĉas: </strong>');
1109		folio.data('serchoparatitolo', serchoparatitolo);
1110		p.append(serchoparatitolo);
1111		const serchoparametroj = $('<span>');
1112		const {length} = parametroj.serchesprimoj;
1113		parametroj.serchesprimoj.forEach( (esp, index) => {
1114			const code = $('<code class="serchesprimo">').text(esp.replace(/ /g, '\u00a0'));
1115			serchoparametroj.append(code);
1116			if (index < length-1) {
1117				const spaco = $('<span/>').text('\u00a0•\u00a0');
1118				serchoparametroj.append(spaco);
1119			}
1120		});
1121		const prezenteroj = [];
1122		if (parametroj.ignorifremdajhojn) {
1123			prezenteroj.push("ignoras trafojn en/kun fremdaĵoj");
1124		} else {
1125			prezenteroj.push("inkluzivas ankaŭ fremdaĵojn");
1126		}
1127		if (parametroj.ignorimallongigojn) {
1128			prezenteroj.push("ignoras trafojn en/kun mallongigoj");
1129		} else {
1130			prezenteroj.push("inkluzivas ankaÅ­ mallongigojn");
1131		}
1132		if (parametroj.uskle) {
1133			prezenteroj.push("atentas usklecon");
1134		} else {
1135			prezenteroj.push("ne atentas usklecon");
1136		}
1137		prezenteroj.push(`montras ${parametroj.largho} signojn`);
1138		prezenteroj.push(`montras maksimume ${PrezentiNombron(parametroj.maksimumo)} trafojn`);
1139		if (parametroj.daurigi) {
1140			prezenteroj.push("daÅ­rigas post maksimumo");
1141		}
1142		if (parametroj.uzistreketojn) {
1143			prezenteroj.push("uzas streketojn");
1144		}
1145		if (parametroj.inverse) {
1146			prezenteroj.push("serĉas en inversa ordo");
1147		}
1148		if (parametroj.kunigitekstojn) {
1149			prezenteroj.push("montras la tekstojn kune");
1150		}
1151		if (parametroj.rapide) {
1152			prezenteroj.push("serĉas rapide");
1153		}
1154		serchoparametroj.append($('<span class="parametroj">').text(prezenteroj.join(" - ")));
1155		p.append(serchoparametroj);
1156		const shanghi = $('<button class="shanghiserchon" title="Uzi la serĉilon denove surbaze de la elektoj de tiu ĉi serĉo">').html('Ŝ<kbd class="fulmo">a</kbd>nĝi');
1157		folio.data('shanghi', shanghi);
1158		const paramemoro = $.extend(true, {}, parametroj);
1159		shanghi.data('paramemoro', paramemoro);
1160		p.append(shanghi);
1161		raportujo.append(p);
1162		const trafosumo_div = $('<div class="trafosumo">').text('Trafoj: ');
1163		const trafosumo_span = $('<span class="trafosumo">').text('0');
1164		const maksimumo_span = $('<span>').text(` (maksimumo: ${PrezentiNombron(parametroj.maksimumo)})`);
1165		trafosumo_div.append(trafosumo_span).append(maksimumo_span);
1166		raportujo.append(trafosumo_div);
1167		serchorezulto.append(raportujo);
1168		folio.data('raportujo', raportujo);
1169
1170		const progresoj = $('<div class="progresoj">');
1171		folio.data('progresoj', progresoj);
1172
1173		const progresujo = $('<div class="progresujo">');
1174
1175		const finidiv = $('<div class="chelo finidiv">');
1176		const finibutono = $('<button class="finiserchon" title="Interrompi la serĉadon"><kbd class="fulmo">F</kbd>ini</button>').data('parametroj', parametroj).data('folio', folio);
1177		finidiv.append(finibutono);
1178
1179		const progresodiv = $('<div class="chelo progresodiv">');
1180		let progreso;
1181		if (!parametroj.kunigitekstojn) {
1182			progreso = $('<progress class="progreso" value="0" max="100">0 %</progress>').data('grando', 0);
1183			const procentilo = $('<span class="procentilo">').text('0%');
1184			progresodiv.append(progreso).append(procentilo);
1185			folio.data('procentilo', procentilo);
1186		} else {
1187			progreso = $('<span class="progreso">Priserĉas ĉiujn elektitajn tekstojn. Bv. atendi...</>');
1188			progresodiv.append(progreso);
1189		}
1190		folio.data('progreso', progreso);
1191
1192		progresujo.append(finidiv).append(progresodiv);
1193		progresoj.append(progresujo);
1194
1195		const progresoraporto = $('<div class="progresoraporto">');
1196		folio.data('progresoraporto', progresoraporto);
1197		progresoj.append(progresoraporto);
1198		serchorezulto.append(progresoj);
1199
1200		const rezultujo = $('<div class="rezultujo">');
1201		parametroj.elektitaj_tekstoj.forEach( function(t, i) {
1202			rezultujo.append($('<div>').prop('class', 'serchoprezento t_' + t));
1203		})
1204		folio.data('rezultujo', rezultujo);
1205		serchorezulto.append(rezultujo);
1206
1207		langetoj.append(langeto);
1208		foliojene.append(folio);
1209		langeto_a.trigger('click');
1210		folio.data('trafosumo_span', trafosumo_span);
1211
1212		MarkiLangetonKielAktivan(langeto, true);
1213
1214		KonserviSerchilostaton();
1215		if (url_id) {
1216			folio.data('url_id', url_id);
1217			url_id = false;
1218		}
1219		folio.append(mdiv).append(serchorezulto);
1220		return folio;
1221	};
1222
1223	const MontriSerchon = (serchorezulto, folio, parametroj, indekso, akumulo, e) => {
1224		if (parametroj.vortosumo === undefined) {
1225			// Se la serĉo estas memorita, la vortosumo ne estas en la parametroj
1226			parametroj.vortosumo = grandeco.data('sumo');
1227		}
1228		if (!serchorezulto) {
1229			folio.data('progresoraporto').remove();
1230			const procentilo = folio.data('procentilo');
1231			if (e && e.name === 'AbortError') {
1232				folio.addClass('interrompita');
1233			} else {
1234				let eraro;
1235				if (e === 'finiserchon') {
1236					eraro = '';
1237				} else {
1238					eraro = $('<em class="eraro">').text('Eraro! La serĉado malsukcesis. Eble mankas konekto kun la Interreto, aŭ eble la serĉo daŭris tro longe.');
1239				}
1240				if (procentilo) {
1241					procentilo.closest('div.progresujo').html(eraro);
1242				} else {
1243					const progreso = folio.data('progreso');
1244					if (progreso) {
1245						progreso.closest('div.progresujo').html(eraro);
1246					}
1247				}
1248			}
1249		} else {
1250			const rezulto = serchorezulto.tekstoj[indekso];
1251			let trafosumo = rezulto.trafosumo;
1252			if (trafosumo) {
1253				const trafosumo_span = folio.data('trafosumo_span');
1254				const nova_sumo = parseInt(trafosumo_span.text().replace(/\./g, ''), 10) + trafosumo;
1255				parametroj.jamajtrafoj = nova_sumo;
1256				trafosumo_span.text(PrezentiNombron(nova_sumo));
1257				const serchoprezento = folio.find('div.serchoprezento.t_' + rezulto.dosiero)
1258				const teksto_div = $('#teksto_' + rezulto.dosiero);
1259				const data = teksto_div.data('data');
1260				let trovovorto = 'trovo';
1261				if (trafosumo !== 1) {
1262					trovovorto += 'j';
1263				}
1264				const titolo = $('<h2>');
1265				let sekcihoko;
1266				if (rezulto.alineoj.length) {
1267					sekcihoko = $('<input type="checkbox" class="trafohokosekcia"/>').data('folio', folio);
1268					sekcihoko.data('serchoprezento', serchoprezento);
1269					titolo.append(sekcihoko);
1270				}
1271				const titolenhavo = $('<span class="titolenhavo"/>
1271').data('sekcihoko', sekcihoko);
1272				const trafospan = $('<span class="trafoj">').text(PrezentiNombron(trafosumo));
1273				const pluspan = $('<span>').text(` ${trovovorto} en `);
1274				const cite = $('<cite>').text(data.titolo);
1275				const komo = $('<span/>').text(', ');
1276				const info = $('<span class="info">').text(data.plumetis + ', ' + data.jaro).prop('title', data.grando + ' vortoj, ' + data.presloko);
1277				titolenhavo.append(trafospan).append(pluspan).append(cite).append(komo).append(info);
1278				titolo.append(titolenhavo);
1279				serchoprezento.append(titolo);
1280				const trovaro = $('<div class="trovaro">');
1281				const {alineoj} = rezulto;
1282				const streketo_rx = /_/g;
1283				const alineo_idoj = {};
1284				alineoj.forEach(alineo => {
1285					alineo.teksto = alineo.teksto.replace(/</g, '&lt;').replace(/>/g, '&gt;');
1286					if (parametroj.uzistreketojn) {
1287						alineo.teksto = alineo.teksto.replace(streketo_rx, '<span class="streketo">•</span>');
1288					}
1289					// Prezenti surogatajn substrekojn kiel verajn substrekojn
1290					alineo.teksto = alineo.teksto.replace(/﹍/g, '_')
1291					const alinepartoj = alineo.teksto.split("\u2045");
1292					let parto1, parto2, parto3;
1293					if (alinepartoj[0]) {
1294						parto1 = alinepartoj[0];
1295					} else {
1296						parto1 = "";
1297					}
1298					if (alinepartoj[1]) {
1299						parto2 = alinepartoj[1];
1300					} else {
1301						parto2 = "";
1302					}
1303					if (alinepartoj[2]) {
1304						parto3 = alinepartoj[2];
1305					} else {
1306						parto3 = "";
1307					}
1308					let antauparto, latrafo, postparto;
1309					const partoj1 = parto1.replace(/^( +)( .+)$/, "$1ǀ$2").split('ǀ');
1310					if (partoj1.length === 2) {
1311						const antauparto1 = $('<span class="antauspacetoj teksto">').html(partoj1[0].replace(/ /g, '.'));
1312						const antauparto2 = $('<span class="teksto">').html(partoj1[1]);
1313						antauparto = $('<span>').append(antauparto1).append(antauparto2);
1314					} else {
1315						antauparto = $('<span class="teksto">').html(parto1);
1316					}
1317					const trafoparametroj = {
1318						"nomo": rezulto.dosiero,
1319						"id": alineo.id,
1320						"sekcio": alineo.sekcio,
1321						"sekcidivido": rezulto.sekcidivido,
1322						"serchesprimo": alineo.serchesprimo,
1323						"ignorifremdajhojn": serchorezulto.ignorifremdajhojn,
1324						"ignorimallongigojn": serchorezulto.ignorimallongigojn,
1325						"uzistreketojn": serchorezulto.uzistreketojn,
1326						"uskle": serchorezulto.uskle,
1327						"protektita": data.protektita,
1328						"grando": parseInt(data.grandosen, 10)
1329					};
1330					latrafo = $('<strong class="trafo" title="Montri la tutan alineon">').html(parto2).data('trafoparametroj', trafoparametroj);
1331					latrafo.data('folio', folio);
1332					postparto = $('<span class="teksto">').html(parto3);
1333					const trafohoko = $('<input type="checkbox" class="trafohoko"/>');
1334					const linio = $('<div class="trafolinio">').append(trafohoko).append(antauparto).append(latrafo).append(postparto);
1335					linio.data('trafoparametroj', trafoparametroj);
1336					latrafo.data('linio', linio);
1337					trafohoko.data('linio', linio).data('folio', folio).data('trafo', latrafo).data('sekcihoko', sekcihoko);
1338					if (!alineo_idoj[alineo.id]) {
1339						alineo_idoj[alineo.id] = 1;
1340					} else {
1341						++alineo_idoj[alineo.id];
1342					}
1343					trafohoko.data('alineo-id', alineo.id + '_' + alineo_idoj[alineo.id]);
1344					trovaro.append(linio);
1345				});
1346				serchoprezento.append(trovaro);
1347				if (!folio.hasClass('NERULUMU')) {
1348					const poz = titolo.position();
1349					if (poz && poz.top) {
1350						folio.data('rezultujo').scrollTop(poz.top);
1351					}
1352				}
1353			}
1354
1355			const progreso = folio.data('progreso');
1356			const procentilo = folio.data('procentilo');
1357			const nomo = serchorezulto.tekstoj[indekso].dosiero;
1358			if (!nomo) {
1359				return;
1360			}
1361			const t = $('#teksto_' + nomo);
1362			if (!t) {
1363				return;
1364			}
1365			const t_data = t.data('data');
1366			if (!t_data) {
1367				return;
1368			}
1369			if (procentilo) {
1370				let grando;
1371				if (t_data && t_data.grandosen) {
1372					grando = parseInt(t_data.grandosen , 10);
1373				} else {
1374					grando = 0;
1375				}
1376				const nunagrando = progreso.data('grando');
1377				progreso.data('grando', nunagrando+grando);
1378				let procentajho
1379				if (parametroj.vortosumo === 0) {
1380					procentajho = 0;
1381				} else {
1382					procentajho = ((nunagrando/parametroj.vortosumo) * 100).toFixed(0);
1383				}
1384				progreso.prop('value', procentajho);
1385				procentilo.text(procentajho + '%').css({'left': ((progreso.width()/2)-(procentilo.width()/2)) + 'px'});
1386			}
1387		}
1388	};
1389
1390	const KontroliMarkitajn = folio => {
1391		const markitaj = folio.find('input.trafohoko:checked');
1392		const mdiv = folio.data('mdiv');
1393		if (markitaj.length) {
1394			mdiv.addClass('markitaj');
1395		} else {
1396			mdiv.removeClass('markitaj');
1397		}
1398	};
1399
1400	const KontroliTrafoSekciojn = (folio, speco) => {
1401		folio.find('div.serchoprezento').each( (indekso, d) => {
1402			d = $(d);
1403			if (speco === 'malkashi') {
1404				d.removeClass('kashita');
1405			} else if (speco === 'markitaj') {
1406				const videblajtrafoj = d.find('div.trovaro div.trafolinio:not(.markita)');
1407				if (!videblajtrafoj.length) {
1408					d.addClass('kashita');
1409				} else {
1410					d.removeClass('kashita');
1411				}
1412			} else {
1413				const videblajtrafoj = d.find('div.trovaro div.trafolinio.markita');
1414				if (!videblajtrafoj.length) {
1415					d.addClass('kashita');
1416				} else {
1417					d.removeClass('kashita');
1418				}
1419			}
1420		});
1421	};
1422
1423	const KontroliChuMarkoj = folio => {
1424		const markita = document.querySelector('#' + folio.prop('id') + ' input.trafohoko:checked');
1425		if (markita) {
1426			folio.addClass("havasmarkojn");
1427		} else {
1428			folio.removeClass("havasmarkojn");
1429		}
1430	};
1431
1432	const ReaplikiMarkojn = (parametroj, rezultujo, folio) => {
1433		if (parametroj.markitaj) {
1434			rezultujo.find('div.trafolinio input.trafohoko').each( (index, inputo) => {
1435				inputo = $(inputo);
1436				const alineoid = inputo.data('alineo-id');
1437				if (parametroj.markitaj.includes(alineoid)) {
1438					inputo.prop('checked', true);
1439					inputo.data('linio').addClass('markita');
1440				}
1441			});
1442		} else if (parametroj.nemarkitaj) {
1443			rezultujo.find('div.trafolinio input.trafohoko').each( (index, inputo) => {
1444				inputo = $(inputo);
1445				const alineoid = inputo.data('alineo-id');
1446				if (!parametroj.nemarkitaj.includes(alineoid)) {
1447					inputo.prop('checked', true);
1448					inputo.data('linio').addClass('markita');
1449				}
1450			});
1451		}
1452		KontroliMarkitajn(folio);
1453		if (parametroj.kashimarkitajn) {
1454			folio.addClass('kashimarkitajn');
1455			folio.data('kashaverto').text('Unu aŭ pli da markitaj trafoj estas kaŝitaj');
1456			KontroliTrafoSekciojn(folio, 'markitaj');
1457		} else if (parametroj.kashinemarkitajn) {
1458			folio.addClass('kashinemarkitajn');
1459			folio.data('kashaverto').text('Unu aŭ pli da nemarkitaj trafoj estas kaŝitaj');
1460			KontroliTrafoSekciojn(folio, 'nemarkitaj');
1461		}
1462		KontroliChuMarkoj(folio);
1463	};
1464
1465	const Serchi = (parametroj, folio, t_numero, akumulo) => {
1466		if (parametroj) {
1467			parametroj.tekstoj = parametroj.elektitaj_tekstoj[t_numero];
1468		}
1469		if (parametroj?.tekstoj && !parametroj.FINI && t_numero <= (parametroj.elektitaj_tekstoj.length -1) && !folio.hasClass('FINI')) {
1470			if (!parametroj.tekstoj) {
1471				return;
1472			}
1473			const t = $('#teksto_' + parametroj.tekstoj);
1474			if (!t) {
1475				return;
1476			}
1477			const t_data = t.data('data');
1478			if (!t_data) {
1479				return;
1480			}
1481			let titolo;
1482			if (t_data && t_data.titolo) {
1483				titolo = t_data.titolo;
1484			} else{
1485				return;
1486			}
1487			if (akumulo) {
1488				parametroj.jamajtrafoj = akumulo.trafoj;
1489			}
1490			if (parametroj.kunigitekstojn) {
1491				parametroj.tekstoj = '';
1492				while (parametroj.elektitaj_tekstoj.length) {
1493					parametroj.tekstoj += parametroj.elektitaj_tekstoj.shift();
1494					if (parametroj.elektitaj_tekstoj.length) {
1495						parametroj.tekstoj += ';';
1496					}
1497				}
1498			}
1499			const progresoraporto = folio.data('progresoraporto');
1500			if (!parametroj.kunigitekstojn) {
1501				progresoraporto.text('Priserĉas la tekston ').append($('<cite>').text(titolo));
1502			}
1503			const json_parametroj = JSON.parse(JSON.stringify(parametroj));
1504			json_parametroj.nemarkitaj = undefined;
1505			json_parametroj.markitaj = undefined;
1506			json_parametroj.kashimarkitajn = undefined;
1507			json_parametroj.kashinemarkitajn = undefined;
1508			let json_data = JSON.stringify(json_parametroj);
1509			json_data = json_data.replace(/[\u007F-\uFFFF]/g, chr => "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4));
1510			let signal, controller;
1511			if ('AbortController' in window) {
1512				controller = new AbortController();
1513				let kontroliloj = folio.data('kontroliloj');
1514				if (!kontroliloj) {
1515					kontroliloj = []
1516					folio.data('kontroliloj', kontroliloj)
1517				}
1518				folio.data('kontroliloj').push(controller);
1519				signal = controller.signal;
1520			}
1521			fetch(
1522				programoj.serchi + '?' + KreiMendon({data: json_data}),
1523				{signal}
1524			).then(
1525				respondo => {
1526					if (respondo?.ok) {
1527						return Objektigi(respondo.json());
1528					} else {
1529						return false;
1530					}
1531				}
1532			).then(
1533				rezulto => {
1534					if (rezulto) {
1535						if (rezulto.ERARO) {
1536							if (rezulto.ERARO === 'RX') {
1537								parametroj.FINI = 1;
1538								const kontroliloj = folio.data('kontroliloj');
1539								if (kontroliloj) {
1540									kontroliloj.forEach( function(kontrolilo) {
1541										kontrolilo.abort('finiserchon');
1542									})
1543								}
1544								let rezulto_rx = '';
1545								if (rezulto.RX) {
1546									rezulto_rx = '<kbd>' + rezulto.RX + '</kbd> ';
1547								}
1548								Dialogo(
1549									$('<span>La serĉesprimo ' + rezulto_rx + 'enhavas eraron kaj ne povas esti uzata.</span>')
1550								);
1551								let h1 = folio.find('h1');
1552								h1.addClass('ERARO').text(h1.text() + ': ERARO!');
1553								folio.addClass('ERARO');
1554							}
1555							parametroj.FINI = 1;
1556						}
1557						if (!folio || !folio[0].parentNode) {
1558							return;
1559						}
1560						if (rezulto.trafosumo !== undefined) {
1561							if (akumulo) {
1562								akumulo.trafoj += rezulto.trafosumo;
1563							}
1564							rezulto.tekstoj.forEach((teksto, indekso) => {
1565								MontriSerchon(rezulto, folio, parametroj, indekso, akumulo);
1566							});
1567						}
1568						if (parametroj.rapide) {
1569							if (akumulo.trafoj >= parametroj.maksimumo) {
1570								folio.addClass('maksimumo')
1571								parametroj.FINI = 1;
1572								const kontroliloj = folio.data('kontroliloj');
1573								if (kontroliloj) {
1574									kontroliloj.forEach( function(kontrolilo) {
1575										kontrolilo.abort('finiserchon');
1576									})
1577								}
1578							}
1579						} else {
1580							if (!parametroj.daurigi && parametroj.jamajtrafoj >= parametroj.maksimumo) {
1581								parametroj.FINI = 1;
1582							}
1583						}
1584						if (parametroj.rapide) {
1585							akumulo.plenumitaj_serchoj += 1
1586							if (parametroj.FINI || akumulo.plenumitaj_serchoj === parametroj.elektitaj_tekstoj.length || (parametroj.kunigitekstojn && akumulo.plenumitaj_serchoj === 1)) {
1587								Serchi(parametroj, folio, mmm, akumulo)
1588							}
1589						} else {
1590							Serchi(parametroj, folio, t_numero + 1);
1591						}
1592					} else {
1593						MontriSerchon(false, folio, parametroj, t_numero + 1, akumulo);
1594					}
1595				}
1596			).catch(
1597				(e) => {
1598					MontriSerchon(false, folio, parametroj, 0, akumulo, e);
1599				}
1600			);
1601		} else {
1602			setTimeout( function() {
1603				const progresoj = folio.data('progresoj');
1604				progresoj.addClass('kashita');
1605				const rezultujo = folio.data('rezultujo');
1606				const serchoparatitolo = folio.data('serchoparatitolo');
1607				serchoparatitolo.text('Serĉis: ');
1608				rezultujo.addClass('finita');
1609				if (MontriTempon) {
1610					if (!parametroj.FERMO) {
1611						CON("Tempo: " + (new Date().getTime() - folio.data('ektempo')));
1612					}
1613				}
1614				const langeto = folio.data('langeto');
1615				MarkiLangetonKielAktivan(langeto, false);
1616				const trafosumo_span = folio.data('trafosumo_span');
1617				const trafosumo_div = trafosumo_span.closest('div.trafosumo');
1618				let trafoteksto = '<span>Suma trafonombro';
1619				if (folio.hasClass('interrompita') && !folio.hasClass('maksimumo')) {
1620					trafoteksto += ' - <em>post interrompo</em>: </span>'
1621				} else {
1622					trafoteksto += ': </span>'
1623				}
1624				const sumo = $('<strong>').html(trafoteksto);
1625				let suma_nombro = 0;
1626				folio.find('span.trafoj').each( function(i, spano) {
1627					suma_nombro += parseInt($(spano).text().replace(/\./g, ''), 10);
1628				});
1629				const sumospan = $('<span class="trafosumo">').text(PrezentiNombron(suma_nombro));
1630				sumo.append(sumospan);
1631				let ligilo_span, ligilo_ena_span, ligilo_url_span, krei_ligilon_butono, kopii_butono;
1632				const folio_url_id = folio.data('url_id');
1633				ligilo_span = $('<span class="ligilo"/>');
1634				krei_ligilon_butono = $('<button class="krei_ligilon">Krei ligilon al tiu ĉi serĉo</button>').data('folio', folio);
1635				folio.data('krei_ligilon_butono', krei_ligilon_butono);
1636				folio.data('ligilo_span', ligilo_span);
1637				ligilo_span.append(krei_ligilon_butono);
1638				if (folio_url_id) {
1639					ligilo_span.addClass('kopii');
1640					ligilo_ena_span = $('<span class="ena" title="Ligilo al tiu ĉi serĉo">Ligilo: </span>');
1641					ligilo_url_span = $(`<span class="url">https://${location.hostname}/?s=${folio_url_id}</span>`);
1642					ligilo_ena_span.append(ligilo_url_span);
1643					ligilo_span.append(ligilo_ena_span);
1644					kopii_butono = $('<button data-ligilo="https://' + location.hostname + '/?s=' + folio_url_id + '" class="kopiiligilon" title="Kopii la ligilo-adreson">Kopii</button>');
1645					ligilo_span.append(kopii_butono);
1646				}
1647				trafosumo_div.html('').append(sumo).append(ligilo_span);
1648				if (parametroj.uzistreketojn === 1) {
1649					const kashi_streketojn = $('<button class="kashi_streketojn">Kaŝi streketojn</button>').data('folio', folio);
1650					trafosumo_div.append(kashi_streketojn);
1651				}
1652				langeto.addClass('finisserchon');
1653				folio.addClass('finisserchon');
1654				if (parametroj.markitaj || parametroj.nemarkitaj) {
1655					ReaplikiMarkojn(parametroj, rezultujo, folio);
1656				}
1657				AdaptiTutanSerchon(folio);
1658			}, 100);
1659		}
1660	};
1661
1662	const Foliofermado = (langeto, folio) => {
1663		if (folio.hasClass('teksto')) {
1664			FermiFolion(langeto, folio);
1665		} else {
1666			const serchofolio_id = folio.prop('id');
1667			const jamaj_tekstolangetoj = langetoj.find('li.langeto.teksto.' + serchofolio_id);
1668			if (jamaj_tekstolangetoj.length) {
1669				FermiFolion(langeto, folio, jamaj_tekstolangetoj);
1670			} else {
1671				FermiFolion(langeto, folio);
1672			}
1673		}
1674	};
1675
1676	const FermiChiujnFoliojn = () => {
1677		$(langetoj.find('li.langeto:not(.teksto)').get().reverse()).each( (index, langeto) => {
1678			langeto = $(langeto);
1679			const folio = langeto.data('folio');
1680			if (langeto && folio && langeto.length && folio.length) {
1681				Foliofermado(langeto, folio);
1682			}
1683		});
1684		//AktivigiSerchilon();
1685	};
1686
1687	const HaltigiChiujnSerchojn = () => {
1688		foliojene.find('button.finiserchon').trigger('click');
1689		langetoj.find('li.langeto').each( (index, langeto) => {
1690			langeto = $(langeto);
1691			let serchas = langeto.data('serchas');
1692			if (serchas) {
1693				clearTimeout(serchas);
1694			}
1695			langeto.removeClass('serchas').removeClass('serchas2');
1696			//if (langeto.hasClass('rapide')) {
1697			//	let folio = langeto.data('folio');
1698			//	if (folio) {
1699
1700			//	}
1701			//}
1702		});
1703	};
1704
1705	restarigi_foliojn_select.on('change', () => {
1706		const selectedIndex = restarigi_foliojn_select.prop('selectedIndex');
1707		if (selectedIndex) {
1708			let option = restarigi_foliojn_select[0].options[selectedIndex];
1709			let miaj_butonoj;
1710			if (option) {
1711				option = $(option);
1712				if (option.hasClass('chiujn')) {
1713					miaj_butonoj = [];
1714					miaj_butonoj.push({teksto: 'Jes, restarigu ĉiujn', click: () => {
1715						body.removeClass('shargita');
1716						setTimeout( () => {
1717							let remetota, i, para, folio;
1718							while (foliomemoro.length) {
1719								remetota = foliomemoro.pop();
1720								if (remetota.langeto) {
1721									remetota.langeto.removeClass('forigita');
1722									remetota.folio.removeClass('forigita');
1723									if (remetota.tekstoj) {
1724										for (i = 0; i < remetota.tekstoj.length; i++) {
1725											remetota.tekstoj[i].langeto.removeClass('forigita');
1726										}
1727									}
1728									AktivigiSerchofolion(remetota.folio);
1729								} else {
1730									para = $.extend(true, {}, remetota);
1731									para.serchesprimo = remetota.serchesprimo;
1732									delete para.paramemoroj;
1733									folio = KreiSerchofolion(para);
1734									if (MontriTempon) {
1735										folio.data('ektempo', new Date().getTime());
1736									}
1737									FariSerchon(para, folio);
1738								}
1739							}
1740							PrilaboriFoliomemoron();
1741							KonserviSerchilostaton();
1742							body.addClass('shargita');
1743						}, 500);
1744					}});
1745					miaj_butonoj.push({teksto: 'Ne, faru nenion', click: () => restarigi_foliojn_select.prop('selectedIndex', 0)});
1746					Dialogo(
1747						'Ĉu restarigi ĉiujn listigitajn fermitajn serĉojn? (Tio povas daŭri iom longe. Dume la Tekstaro estos nevidebligita.)',
1748						miaj_butonoj
1749					);
1750				} else if (option.hasClass('remetota')) {
1751					const remetota = $(option).data('remetota');
1752					if (remetota) {
1753						miaj_butonoj = [];
1754						miaj_butonoj.push({teksto: 'Jes, restarigu ĝin', click: () => {
1755							let nova_foliomemoro = [];
1756							foliomemoro.slice().reverse().forEach( (m, indekso) => {
1757								if (indekso !== selectedIndex-1) {
1758									nova_foliomemoro.unshift(m);
1759								}
1760							});
1761							foliomemoro = nova_foliomemoro;
1762							if (remetota.langeto) {
1763								remetota.langeto.removeClass('forigita');
1764								remetota.folio.removeClass('forigita');
1765								if (remetota.tekstoj) {
1766									remetota.tekstoj.forEach(teksto => {
1767										teksto.langeto.removeClass('forigita');
1768										teksto.folio.removeClass('forigita');
1769									});
1770								}
1771								AktivigiSerchofolion(remetota.folio);
1772							} else {
1773								const para = $.extend(true, {}, remetota);
1774								para.serchesprimo = remetota.serchesprimo;
1775								delete para.paramemoroj;
1776								const folio = KreiSerchofolion(para);
1777								if (MontriTempon) {
1778									folio.data('ektempo', new Date().getTime());
1779								}
1780								FariSerchon(para, folio)
1781							}
1782							PrilaboriFoliomemoron();
1783						}});
1784						miaj_butonoj.push({teksto: 'Ne, faru nenion', click: 'fermi'});
1785						Dialogo(
1786							`Ĉu restarigi la serĉon “${option.text()}”`,
1787							miaj_butonoj,
1788							() => restarigi_foliojn_select.prop('selectedIndex', 0)
1789						);
1790					}
1791				}
1792			}
1793		}
1794	});
1795
1796	langetoj.on('click', 'li', evento => {
1797		evento.stopPropagation();
1798		langetoj.find('li.aktiva').removeClass('aktiva');
1799		const langeto = $(evento.currentTarget);
1800		langeto.addClass('aktiva');
1801		const aktiva_folio = folioj.find('div.folio.aktivafolio');
1802		aktiva_folio.removeClass('aktivafolio');
1803		const folio = langeto.data('folio');
1804		folio.addClass('aktivafolio');
1805		if (folio.prop('id') === 'serchilo') {
1806			serchilo_aktiva = true
1807		} else if (folio.hasClass('teksto')) {
1808			serchilo_aktiva = false
1809			const butonodiv = folio.find('div.butonodiv');
1810			const div_tutateksto = folio.find('div.tutateksto');
1811			if (butonodiv.length && div_tutateksto.length) {
1812				AdaptiTutanTekston(div_tutateksto, butonodiv);
1813			}
1814		} else {
1815			serchilo_aktiva = false
1816			AdaptiTutanSerchon(folio);
1817		}
1818	});
1819	langetoj.on('click', 'a', evento => {
1820		evento.preventDefault();
1821	});
1822	langetoj.on('click', 'span.fermilo', evento => {
1823		evento.stopPropagation();
1824		const fermilo = $(evento.currentTarget);
1825		const langeto = fermilo.closest('li.langeto');
1826		const folio = langeto.data('folio');
1827		if (langeto.length && folio.length) {
1828			Foliofermado(langeto, folio);
1829		}
1830	});
1831
1832	fermichiujn.on('click', () => {
1833		const aoj = langetoj.find('li.langeto:not(.forigita)');
1834		if (aoj.length) {
1835			Dialogo(
1836				'Ĉu fermi ĉiujn serĉajn kaj tekstajn foliojn (lasante nur la serĉilon)?',
1837				[
1838					{teksto: 'Jes, fermu ilin', click: FermiChiujnFoliojn},
1839					{teksto: 'Ne, lasu ilin'}
1840				]
1841			);
1842		} else {
1843			Dialogo('Ne estas serĉaj aŭ tekstaj folioj por fermi.');
1844		}
1845	});
1846
1847	haltigichiujn.on('click', () => {
1848		const aoj = langetoj.find('li.langeto.serchas, li.langeto.serchas2');
1849		if (aoj.length) {
1850			Dialogo(
1851				'Ĉu haltigi ĉiujn daŭrantajn serĉojn?',
1852				[
1853					{teksto: 'Jes, haltigu ilin', click: HaltigiChiujnSerchojn},
1854					{teksto: 'Ne, ili plu daÅ­ru', click: 'fermi'}
1855				]
1856			);
1857		} else {
1858			Dialogo('Neniu serĉo okazas nun.');
1859		}
1860	});
1861
1862	tekstoj.on('click', 'input[type=checkbox]', (evento, altKey) => {
1863		evento.stopPropagation();
1864		if (jarojaktivaj.prop('checked')) {
1865			evento.preventDefault();
1866			return;
1867		}
1868		const checkbox = $(evento.currentTarget)
1869		let tekstodiv = checkbox.closest('div.teksto');
1870		if (tekstodiv.hasClass('malshaltita')) {
1871			evento.preventDefault();
1872			return;
1873		}
1874		KashiShvebinformojn();
1875		tekstodiv.toggleClass('elektita');
1876		if (majuskliga_klavo) {
1877			ForigiTekstelekton();
1878			if (jhus_elektita_teksto) {
1879				const nun_elektita = tekstodiv.hasClass('elektita');
1880				const jhus_elektita = jhus_elektita_teksto.hasClass('elektita');
1881				if (nun_elektita === jhus_elektita) {
1882					const this_id = tekstodiv.prop('id');
1883					const jhus_id = jhus_elektita_teksto.prop('id');
1884					let komenco;
1885					const interaj = [];
1886					chiuj_tekstoj.each(	(index, teksto) => {
1887						const id = $(teksto).prop('id');
1888						if (komenco && id !== this_id && id !== jhus_id) {
1889							interaj.push(teksto);
1890						} else if (id === this_id || id === jhus_id) {
1891							if (komenco) {
1892								return false;
1893							}
1894							komenco = teksto;
1895						}
1896					});
1897					interaj.forEach(intera => {
1898						intera = $(intera);
1899						if (!intera.hasClass('malshaltita')) {
1900							intera.toggleClass('elektita', nun_elektita);
1901							intera.find('div.check input').prop('checked', nun_elektita);
1902						}
1903					});
1904				}
1905			}
1906		} else if (altKey) {
1907			let klasoj = checkbox[0].classList
1908			if (klasoj.length) {
1909				let checked = checkbox[0].checked
1910				$.each(klasoj, function(i, klaso) {
1911					if (klaso.length > 4 && klaso.indexOf('PIV_') === 0) {
1912						let aliaj = $('input.' + klaso)
1913						aliaj.each( function(j, alia) {
1914							alia.checked = checked
1915							let tekstodiv = $(alia).closest('div.teksto');
1916							if (!tekstodiv.hasClass('malshaltita')) {
1917								tekstodiv.toggleClass('elektita', checked);
1918							}
1919						})
1920					}
1921				})
1922			}
1923		}
1924		jhus_elektita_teksto = tekstodiv;
1925	});
1926
1927	tekstoj.on('change', 'input[type=checkbox]', () => {
1928		RekalkuliTekstokvanton();
1929	});
1930
1931	tekstoj.on('click', 'div.montri', evento => {
1932		evento.stopPropagation();
1933		const obj = $(evento.currentTarget);
1934		const teksto_div = obj.closest('div.teksto');
1935		const div = teksto_div.addClass('traktata');
1936		const data = div.data('data');
1937		const dialogotitolo = $('<div class="dialogotitolo">').append($('<cite>').text(data.titolo));
1938		let shaltoteksto;
1939		if (div.hasClass('malshaltita')) {
1940			shaltoteksto = "Reŝalti uzon de tiu ĉi teksto";
1941		} else {
1942			shaltoteksto = "Malŝalti uzon de tiu ĉi teksto";
1943		}
1944		const elektoj = [];
1945		elektoj.push({teksto: 'Montri HTML-e', click: () => MontriTekston('html', data)});
1946		elektoj.push({teksto: 'Montri XML-e', click: () => MontriTekston('xml', data)});
1947		elektoj.push({teksto: shaltoteksto, click: () => KomutiTekston(obj)});
1948		elektoj.push({teksto: 'Interrompi', click: 'fermi'});
1949		elektoj.push(teksto_div.find('span.informoj').clone());
1950		Dialogo(
1951			dialogotitolo,
1952			elektoj,
1953			() => div.removeClass('traktata')
1954		);
1955	});
1956
1957	tekstoj.on('mousedown', 'div.teksto', evento => {
1958		var div_teksto = $(evento.currentTarget);
1959		if (div_teksto.hasClass('montrasinformojn')) {
1960			div_teksto.data('informoj').addClass('kashita');
1961			div_teksto.removeClass('montrasinformojn');
1962		}  else {
1963			div_teksto.data('informoj_timeout', setTimeout( () => KreiInformon(div_teksto), 800));
1964		}
1965	}).on('mouseup', 'div.teksto', evento => {
1966		var div_teksto = $(evento.currentTarget);
1967		let timeout = div_teksto.data('informoj_timeout');
1968		if (timeout) {
1969			clearTimeout(timeout);
1970			div_teksto.removeData('informoj_timeout');
1971		}
1972	}).on('mouseout', 'div.teksto', evento => {
1973		var div_teksto = $(evento.currentTarget);
1974		let timeout = div_teksto.data('informoj_timeout');
1975		if (timeout) {
1976			clearTimeout(timeout);
1977			div_teksto.removeData('informoj_timeout');
1978		}
1979	});
1980
1981	tekstoj.on('click', 'div.teksto', evento => {
1982		if (jarojaktivaj.prop('checked')) {
1983			return;
1984		}
1985		const tekstodiv = $(evento.currentTarget);
1986		if (tekstodiv.hasClass('montrasinformojn')) {
1987			return;
1988		}
1989		const informoj_timeout = tekstodiv.data('informoj_timeout');
1990		if (informoj_timeout) {
1991			return;
1992		}
1993		const checkbox = tekstodiv.find('input[type=checkbox]');
1994		checkbox.trigger('click', evento.altKey);
1995	});
1996	chiuj.on('click', evento => {
1997		if (jarojaktivaj.prop('checked')) {
1998			evento.preventDefault();
1999			return;
2000		}
2001		tekstoj.find('div.teksto:not(.malshaltita)').addClass('elektita').find('input').prop('checked', true);
2002		RekalkuliTekstokvanton();
2003		KonserviSerchilostaton();
2004	});
2005
2006	neniuj.on('click', evento => {
2007		if (jarojaktivaj.prop('checked')) {
2008			evento.preventDefault();
2009			return;
2010		}
2011		tekstoj.find('div.teksto').removeClass('elektita').find('input').prop('checked', false);
2012		RekalkuliTekstokvanton();
2013		KonserviSerchilostaton();
2014	});
2015
2016	inversigi.on('click', evento => {
2017		if (jarojaktivaj.prop('checked')) {
2018			evento.preventDefault();
2019			return;
2020		}
2021		tekstoj.find('div.teksto:not(.malshaltita)').each( (index, div) => {
2022			div = $(div);
2023			if (div.hasClass('elektita')) {
2024				div.removeClass('elektita').find('input').prop('checked', false);
2025			} else {
2026				div.addClass('elektita').find('input').prop('checked', true);
2027			}
2028		});
2029		RekalkuliTekstokvanton();
2030		KonserviSerchilostaton();
2031	});
2032
2033	zamenhofaj.on('click', evento => {
2034		if (jarojaktivaj.prop('checked')) {
2035			evento.preventDefault();
2036			return;
2037		}
2038		const elektitaj = tekstoj.find('div.teksto.z.elektita');
2039		const neelektitaj = tekstoj.find('div.teksto.z:not(.elektita):not(.malshaltita)');
2040		if (elektitaj.length < neelektitaj.length) {
2041			neelektitaj.addClass('elektita').find('input').prop('checked', true);
2042		} else {
2043			elektitaj.removeClass('elektita').find('input').prop('checked', false);
2044		}
2045		RekalkuliTekstokvanton();
2046		KonserviSerchilostaton();
2047	});
2048
2049	montriinformojn.on('click', ({currentTarget}) => {
2050		const button = $(currentTarget);
2051		if (tekstoj.hasClass('montriinformojn')) {
2052			tekstoj.removeClass('montriinformojn');
2053			button.html('<kbd class="fulmo">M</kbd>ontri informojn');
2054		} else {
2055			body.find('div.shvebinformoj:not(.kashita)').addClass('kashita');
2056			tekstoj.addClass('montriinformojn');
2057			button.html('Kaŝi infor<kbd class="fulmo">m</kbd>ojn');
2058		}
2059	});
2060
2061	shalti.on('click', () => {
2062		const elektitaj = tekstoj.find('div.teksto.elektita');
2063		const malshaltitaj = tekstoj.find('div.teksto.malshaltita');
2064		if (elektitaj.length || malshaltitaj.length) {
2065			const butonoj = [];
2066			if (malshaltitaj.length) {
2067				butonoj.push( {
2068					teksto: 'Reŝalti ĉiujn malŝaltitajn tekstojn',
2069					click: () => {
2070						malshaltitaj.each( (index, obj) => {
2071							const div = $(obj).find('div.montri');
2072							if (div.length) {
2073								KomutiTekston(div);
2074							}
2075						});
2076					}
2077				});
2078			}
2079			if (elektitaj.length) {
2080				butonoj.push( {
2081					teksto: 'Malŝalti ĉiujn elektitajn tekstojn',
2082					click: () => {
2083						elektitaj.each( (index, obj) => {
2084							const teksto = $(obj);
2085							teksto.removeClass('elektita').find('input[type=checkbox]').prop('checked', false);
2086							KomutiTekston(teksto.find('div.montri'));
2087						});
2088					}
2089				});
2090			}
2091			Dialogo('', butonoj);
2092		}
2093	});
2094
2095	largho.on('change', () => GhustigiNombranValoron(largho, 10, 200, 100));
2096	maksimumo.on('change', () => GhustigiNombranValoron(maksimumo, 1, mmm, 100));
2097	// Permesi fulmmoklavon en largho kaj maksimumo
2098	largho.on('keydown', e => {
2099		if (e.key.match(/^[a-zA-Z!]$/)) {
2100			return false
2101		}
2102	})
2103	largho.on('keyup', e => {
2104		if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
2105			e.stopPropagation()
2106		}
2107	})
2108	maksimumo.on('keydown', e => {
2109		if (e.key.match(/^[a-zA-Z!]$/)) {
2110			return false
2111		}
2112	})
2113	maksimumo.on('keyup', e => {
2114		if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
2115			e.stopPropagation()
2116		}
2117	})
2118
2119	priserchi.on('click', () => {
2120		const parametroj = PreniSerchilostaton();
2121
2122		if (parametroj === -1) {
2123			Dialogo(
2124				'Vi devas enskribi almenaŭ unu serĉesprimon.',
2125				null,
2126				() => setTimeout( () => serchesprimo1.focus(), 10)
2127			);
2128			return false;
2129		}
2130		if (parametroj === -2) {
2131			Dialogo('Vi devas elekti almenaÅ­ unu tekston.');
2132			return false;
2133		}
2134
2135		parametroj.vortosumo = grandeco.data('sumo');
2136
2137		let para, folio;
2138
2139		serchilo_aktiva = false
2140		const parateksto = JSON.stringify(parametroj)
2141		if (parametroj.kunigiserchojn) {
2142			//para = $.extend(true, {}, parametroj);
2143			para = JSON.parse(parateksto);
2144			delete para.paramemoroj;
2145			para.serchesprimoj = parametroj.serchesprimoj;
2146			para.serchesprimo = parametroj.serchesprimoj.join(' • ');
2147			folio = KreiSerchofolion(para);
2148			if (MontriTempon) {
2149				folio.data('ektempo', new Date().getTime());
2150			}
2151			FariSerchon(para, folio)
2152		} else {
2153			parametroj.serchesprimoj.forEach(serchesprimo => {
2154				para = $.extend(true, {}, parametroj);
2155				para.serchesprimoj = [serchesprimo];
2156				para.serchesprimo = serchesprimo;
2157				delete para.paramemoroj;
2158				folio = KreiSerchofolion(para);
2159				if (MontriTempon) {
2160					folio.data('ektempo', new Date().getTime());
2161				}
2162				FariSerchon(para, folio)
2163			});
2164		}
2165
2166		return false;
2167	});
2168
2169	forigiserchesprimon.on('click', () => {
2170		const span = serchesprimoj.find('span.serchesprimospan.plia').last();
2171		EventualeFermiSerchesprimon(span);
2172	});
2173
2174	serchesprimoj.on('click', 'img.serchesprimfermilo', evento => {
2175		const fermilo = $(evento.currentTarget);
2176		const span = fermilo.data('span');
2177		EventualeFermiSerchesprimon(span);
2178	});
2179	serchesprimoj.on('dblclick', 'input.serchesprimo.plia', evento => {
2180		const obj = $(evento.currentTarget);
2181		const span = obj.closest('span.serchesprimospan');
2182		if (span.length) {
2183			EventualeFermiSerchesprimon(span);
2184		}
2185	});
2186	const PrilaboriHTMLon = (teksto) => {
2187		let div = document.createElement('div');
2188		div.innerText = teksto;
2189		return div.innerHTML;
2190	};
2191	const KontroliNEKodajhon = () => {
2192		let averto = false;
2193		serchesprimoj.find('input.serchesprimo').each( (index, input) => {
2194			const inputo = $(input);
2195			const val = inputo.val();
2196			if (val.match(/\\NE/)) {
2197				let val2 = val.replace(/\\\\/g, '');
2198				if (val2.match(/\\NE/)) {
2199					averto = val;
2200				}
2201			}
2202		});
2203		if (averto) {
2204			Dialogo($('<span>La serĉesprimo <kbd>' + PrilaboriHTMLon(averto) + '</kbd> enhavas la specialan kodaĵon <kbd>\\NE</kbd> (por “ne-Esperanta litero”). Ĝi funkcias ĝuste nur kun la elekto “Atentu usklecon”.</span>'));
2205			uskle.prop('checked', true).trigger('change');
2206		}
2207	};
2208	serchesprimoj.on('focus', 'input.serchesprimo', evento => {
2209		$(evento.currentTarget).select();
2210	})
2211	serchesprimoj.on('change', 'input.serchesprimo', evento => {
2212		const obj = $(evento.currentTarget);
2213		obj.val(obj.val().replace(/\\b(\\b)+/, '\\b'));
2214		if (!uskle.prop('checked')) {
2215			KontroliNEKodajhon();
2216		}
2217	});
2218	uskle.on('change', () => {
2219		if (!uskle.prop('checked')) {
2220			KontroliNEKodajhon();
2221		}
2222	});
2223
2224	fulmoklavoj.on('change', () => {
2225		fulmoklavoj_aktivaj = fulmoklavoj.prop('checked') ? true : false;
2226		body.toggleClass('fulmoklavoj', fulmoklavoj_aktivaj);
2227	});
2228
2229	// Alternativa maniero fermi serĉesprimojn, se la x-bildetoj ne bone funkcias
2230	// Longa premo (musa aŭ tuŝa) dum 1,5 sekundoj
2231	serchesprimoj.on('mousedown', 'input.serchesprimo.plia', evento => {
2232		const obj = $(evento.currentTarget);
2233		const span = obj.closest('span.serchesprimospan');
2234		if (span.length) {
2235			obj.data('forigo_timeout', setTimeout( () => EventualeFermiSerchesprimon(span), 1500));
2236		}
2237	}).on('mouseup', 'input.serchesprimo.plia', evento => {
2238		const obj = $(evento.currentTarget);
2239		const forigo_timeout = obj.data('forigo_timeout');
2240		if (forigo_timeout) {
2241			clearTimeout(forigo_timeout);
2242			obj.removeData('forigo_timeout');
2243		}
2244	}).on('mouseout', 'input.serchesprimo.plia', evento => {
2245		const obj = $(evento.currentTarget);
2246		const forigo_timeout = obj.data('forigo_timeout');
2247		if (forigo_timeout) {
2248			clearTimeout(forigo_timeout);
2249			obj.removeData('forigo_timeout');
2250		}
2251	});
2252
2253	foliojene.on('click', 'button.shanghiserchon', ({currentTarget}) => {
2254		const butono = $(currentTarget);
2255		const parametroj = butono.data('paramemoro');
2256		AktivigiSerchilon(parametroj);
2257	});
2258
2259	iloj.on('keyup', 'input[type=text]', evento => {
2260		if (evento.key === 'Enter') {
2261			priserchi.trigger('click');
2262		}
2263	});
2264	iloj.on('change', 'input[type=checkbox]', ({currentTarget}) => {
2265		const input = $(currentTarget);
2266		if (input.prop('checked')) {
2267			input.closest('label').addClass('checked');
2268		} else {
2269			input.closest('label').removeClass('checked');
2270		}
2271	});
2272
2273	foliojene.on('click', 'button.trafopliilo', ({currentTarget}) => {
2274		const butono = $(currentTarget);
2275		const serchofolio = butono.data('folio');
2276		const serchofolio_id = serchofolio.prop('id');
2277		let trafoparametroj = butono.data('trafoparametroj');
2278		const jama_tekstolangeto = langetoj.find(`li.langeto.teksto.${serchofolio_id}.trafalineo${trafoparametroj.id}`);
2279		if (jama_tekstolangeto && jama_tekstolangeto.length) {
2280			const jama_tekstofolio = jama_tekstolangeto.data('folio');
2281			const trafoid = jama_tekstofolio.data('trafoid');
2282			if (trafoid) {
2283				trafoparametroj = butono.data('trafoparametroj');
2284				const jama_trafoid = trafoparametroj.id;
2285				if (trafoid === jama_trafoid) {
2286					jama_tekstofolio.data('langeto').find('a').trigger('click');
2287					RulumiAlTrafo(jama_tekstofolio, false);
2288					return;
2289				}
2290			}
2291		}
2292		const tekstofolio = KreiTekstofolion(serchofolio, trafoparametroj);
2293		tekstofolio.find('div.tutateksto').scrollTop(0);
2294		tekstofolio.html('<div class="shargastekston"><img src="/bildoj/shargastekston.gif"/></div>');
2295		fetch(
2296			programoj.teksto + '?' + KreiMendon(trafoparametroj)
2297		).then(
2298			respondo => {
2299				if (respondo.ok) {
2300					return respondo.text();
2301				} else  {
2302					return false;
2303				}
2304			}
2305		).then(
2306			la_rezulto => {
2307				if (la_rezulto) {
2308					la_rezulto = JSON.parse(la_rezulto);
2309					let rezulto = la_rezulto.rezulto;
2310					// Prezenti surogatajn substrekojn kiel verajn substrekojn
2311					rezulto = $(rezulto.replace(/﹍/g, '_'));
2312					tekstofolio.html(rezulto).data('trafoid', trafoparametroj.id);
2313					butono.data('tekstofolio', tekstofolio);
2314					const div_tutateksto = tekstofolio.find('div.tutateksto');
2315					if (la_rezulto.sekcidivido) {
2316						div_tutateksto.addClass('sekcidivido');
2317					}
2318					if (div_tutateksto) {
2319						const butonodiv = $('<div class="butonodiv">');
2320						if (trafoparametroj.uzistreketojn === 1) {
2321							const kashi_streketojn = $('<span class="kashi_streketojn butono">Kaŝi streketojn</span>').data('tekstofolio', tekstofolio);
2322							butonodiv.append(kashi_streketojn);
2323						}
2324						const ttbutono = $('<span class="ttbutono butono">');
2325						if (trafoparametroj.sekcio) {
2326							ttbutono.addClass('sekcilisto');
2327						}
2328						ttbutono.data('folio', tekstofolio).data('trafoparametroj', trafoparametroj);
2329						ttbutono.text('Montri en aparta fenestro');
2330						butonodiv.append(ttbutono);
2331						const suprensago = $('<span class="sago supren" title="Al la komenco de la teksto">').text('⇑');
2332						const trafosago = $('<span class="sago trafosago" title="Al la alineo kun serĉotrafo">').text('◎');
2333						const subensago = $('<span class="sago suben" title="Al la fino de la teksto">').text('⇓');
2334						const sagoj = $('<span class="sagoj butono">').append(suprensago).append(trafosago).append(subensago);
2335						suprensago.data('div_tutateksto', div_tutateksto);
2336						trafosago.data('tekstofolio', tekstofolio);
2337						subensago.data('div_tutateksto', div_tutateksto);
2338						butonodiv.append(sagoj);
2339						tekstofolio.prepend(butonodiv);
2340						AdaptiTutanTekston(div_tutateksto, butonodiv);
2341						div_tutateksto.find('div.tekstarteksto span.trafo').each( (index, trafo) => {
2342							trafo = $(trafo);
2343							trafo.html(trafo.html().replace(/^ /, '<span class="trafospaceto"> </span>').replace(/ $/, '<span class="trafospaceto"> </span>'));
2344						});
2345						const formuloj = rezulto.find('span.formulo.tex')
2346						if (formuloj.length) {
2347							FormuloTex(formuloj.get(), function() {
2348								setTimeout( function() {
2349									RulumiAlTrafo(tekstofolio, true, div_tutateksto);
2350								}, 10)
2351							})
2352						} else {
2353							RulumiAlTrafo(tekstofolio, true, div_tutateksto);
2354						}
2355					}
2356				}
2357			}
2358		).catch(
2359			eraro => {
2360				CON('Eraro', eraro);
2361				Dialogo('Eraro! La tekstoprenado malsukcesis. Ĉu eble mankas konekto kun la Interreto?');
2362			}
2363		);
2364	});
2365
2366	foliojene.on('click', 'div.tekstarteksto *[class*="editorial"] ', async evento => {
2367		const obj = evento.currentTarget
2368		if (obj.classList.contains('editorial') || obj.classList.contains('editorialwaringhien') || obj.classList.contains('editorialtekstaro') || obj.classList.contains('egg/ditorialzamenhof')) {
2369			evento.stopImmediatePropagation()
2370		}
2371	})
2372	foliojene.on('click', 'div.tekstarteksto *[id]', async evento => {
2373		if (evento.altKey) {
2374			const obj = $(evento.currentTarget);
2375			evento.stopPropagation();
2376			let id = obj.prop('id');
2377			const tutateksto = obj.closest('div.tutateksto');
2378			if (tutateksto.hasClass('sekcidivido')) {
2379				let sekcio = '';
2380				const div = obj.closest('div.tekstarteksto');
2381				if (div.length) {
2382					sekcio = div.data('sekcio');
2383				}
2384				if (sekcio) {
2385					id = id + '_' + sekcio;
2386				}
2387			}
2388			const memorteksto = ' t="' + id  + '"';
2389			if (navigator.clipboard) {
2390				try {
2391					await navigator.clipboard.writeText(memorteksto);
2392					Dialogo($('<p>Kopiis: <strong>' + memorteksto + '</strong></p>'));
2393				} catch (err) {
2394					Dialogo('La kopiado malsukcesis. Bv. provi denove.');
2395				}
2396			} else {
2397				Dialogo($('<p>La aÅ­tomata kopiado ne sukcesis. Bv. noti la jenan tekston:<br/><strong>' + memorteksto + '</strong></p>'));
2398			}
2399			return false;
2400		}
2401	});
2402
2403	foliojene.on('click', 'button.finiserchon', ({currentTarget}) => {
2404		const butono = $(currentTarget);
2405		const parametroj = butono.data('parametroj');
2406		parametroj.FINI = true;
2407		parametroj.FERMO = true;
2408		const folio = butono.data('folio');
2409		if (parametroj.kunigitekstojn) {
2410			if (folio.length) {
2411				const kontroliloj = folio.data('kontroliloj');
2412				if (kontroliloj) {
2413					kontroliloj.forEach( function(kontrolilo) {
2414						kontrolilo.abort('finiserchon');
2415					})
2416				}
2417				if (parametroj.rapide) {
2418					folio.addClass('FINI')
2419					Serchi(false, folio, 0);
2420				} else {
2421					Serchi(parametroj, folio, parametroj.elektitaj_tekstoj.length - 1);
2422				}
2423			}
2424		} else {
2425			if (parametroj.rapide) {
2426				const kontroliloj = folio.data('kontroliloj');
2427				if (kontroliloj) {
2428					kontroliloj.forEach( function(kontrolilo) {
2429						kontrolilo.abort('finiserchon');
2430					})
2431				}
2432				folio.addClass('FINI')
2433				Serchi(false, folio, 0);
2434			}
2435		}
2436	});
2437
2438	foliojene.on('click', 'span.trafofermilo', ({currentTarget}) => {
2439		const trafofermilo = $(currentTarget);
2440		const trafodiv = trafofermilo.closest('div.trafodiv')
2441		if (trafodiv.length) {
2442			trafodiv.addClass('kashita');
2443			trafodiv.closest('div.folio').data('jhus_fermitaj_alineoj', false)
2444		}
2445	});
2446
2447	foliojene.on('focus', 'span.ttbutono', ({currentTarget}) => {
2448		currentTarget.blur();
2449	});
2450
2451	foliojene.on('click', 'span.ttbutono', ({currentTarget}) => {
2452		const butono = $(currentTarget);
2453		const trafoparametroj = butono.data('trafoparametroj');
2454		const parametroj = [];
2455		parametroj.push("nomo=" + trafoparametroj.nomo);
2456		parametroj.push("id=" + trafoparametroj.id);
2457		parametroj.push("ignorifremdajhojn=" + trafoparametroj.ignorifremdajhojn);
2458		parametroj.push("ignorimallongigojn=" + trafoparametroj.ignorimallongigojn);
2459		parametroj.push("uzistreketojn=" + trafoparametroj.uzistreketojn);
2460		parametroj.push("uskle=" + trafoparametroj.uskle);
2461		parametroj.push("serchesprimo=" + encodeURIComponent(trafoparametroj.serchesprimo));
2462		parametroj.push("tuj=1");
2463		let adreso;
2464		if (butono.hasClass('sekcilisto')) {
2465			// Montri liston de sekcioj, ĉar la teksto estas grandega
2466			parametroj.push("aktuala_sekcio=" + trafoparametroj.sekcio);
2467			adreso = programoj.sekcio + "?" + parametroj.join('&');
2468		} else {
2469			// Montri tutan tekston
2470			adreso = `${programoj.tutateksto}?${parametroj.join('&')}#${trafoparametroj.id}`;
2471		}
2472		window.open(adreso);
2473	});
2474
2475	foliojene.on('click', 'span.sago.supren', ({currentTarget}) => {
2476		const sago = $(currentTarget);
2477		const div_tutateksto = sago.data('div_tutateksto');
2478		div_tutateksto.scrollTop(0);
2479	});
2480
2481	foliojene.on('click', 'span.sago.suben', ({currentTarget}) => {
2482		const sago = $(currentTarget);
2483		const div_tutateksto = sago.data('div_tutateksto');
2484		const fino = div_tutateksto.prop('scrollHeight');
2485		div_tutateksto.scrollTop(fino);
2486	});
2487
2488	foliojene.on('click', 'span.sago.trafosago', ({currentTarget}) => {
2489		const sago = $(currentTarget);
2490		const tekstofolio = sago.data('tekstofolio');
2491		RulumiAlTrafo(tekstofolio, false);
2492	});
2493
2494	const MarkiTrafon = obj => {
2495		const linio = obj.closest('div.trafolinio');
2496		const trafohoko = linio.find('input.trafohoko');
2497		if (trafohoko.length) {
2498			trafohoko.trigger('click');
2499		}
2500	};
2501
2502	const PreniIdonPorPIV = async obj => {
2503		if (obj[0].classList.contains('editorial')) {
2504			return;
2505		}
2506		// Preni la alinean id-atributon por uzo en la PIV-redaktejo
2507		const trafoparametroj = obj.data('trafoparametroj');
2508		if (trafoparametroj && trafoparametroj.id) {
2509			let id = trafoparametroj.id;
2510			if (trafoparametroj.sekcidivido) {
2511				const sekcio = trafoparametroj.sekcio;
2512				if (sekcio) {
2513					id += '_' + sekcio;
2514				}
2515			}
2516			const memorteksto = ' t="' + id  + '"';
2517			if (navigator.clipboard) {
2518				try {
2519					await navigator.clipboard.writeText(memorteksto);
2520					Dialogo($('<p>Kopiis: <strong>' + memorteksto + '</strong></p>'));
2521				} catch (err) {
2522					Dialogo('La kopiado malsukcesis. Bv. provi denove.');
2523				}
2524			} else {
2525				Dialogo($('<p>La aÅ­tomata kopiado ne sukcesis. Bv. noti la jenan tekston:<br/><strong>' + memorteksto + '</strong></p>'));
2526			}
2527		}
2528	};
2529
2530	foliojene.on('click', 'div.trafodiv, div.trafolinio', evento => {
2531		if (evento.altKey) {
2532			PreniIdonPorPIV($(evento.currentTarget));
2533		}
2534	});
2535
2536	foliojene.on('click', 'div.trafolinio strong.trafo', evento => {
2537		const trafo = $(evento.currentTarget);
2538		if (evento.ctrlKey) {
2539			MarkiTrafon(trafo);
2540		} else {
2541			const folio = trafo.data('folio').addClass('NERULUMU');
2542			let miatrafodiv;
2543			if (trafo.hasClass('jammontras')) {
2544				miatrafodiv = trafo.data('trafodiv');
2545				if (miatrafodiv) {
2546					miatrafodiv.toggleClass('kashita');
2547					folio.data('jhus_fermitaj_alineoj', false)
2548				}
2549			} else {
2550				miatrafodiv = trafo.data('trafodiv');
2551				if (miatrafodiv) {
2552					miatrafodiv.removeClass('kashita');
2553					folio.data('jhus_fermitaj_alineoj', false)
2554				} else {
2555					trafo.addClass('jammontras');
2556					const trafoparametroj = trafo.data('trafoparametroj');
2557					const pre = trafo.closest('div.trafolinio');
2558					const trafodiv = $('<div class="trafodiv kunalineo">');
2559					pre.data('trafoparametroj', trafoparametroj);
2560					trafodiv.data('trafoparametroj', trafoparametroj);
2561					trafo.data('trafodiv', trafodiv);
2562					if (trafo.data('linio').hasClass('markita'))  {
2563						trafodiv.addClass('markita');
2564					}
2565					const mesaghodiv = $('<div>').text('Bv. atendi...');
2566					const trafofermilo = $('<span class="trafofermilo" title="Fermi la montradon de tiu ĉi tuta alineo">').text('×');
2567					let trafopliilo;
2568					if (trafoparametroj.protektita !== 1) {
2569						trafopliilo = $('<button class="trafopliilo">Pli da kunteksto</button>');
2570						trafopliilo.data('trafoparametroj', trafoparametroj).data('folio', folio);
2571					}
2572					trafodiv.append(mesaghodiv);
2573					pre.after(trafodiv);
2574
2575					fetch(
2576						programoj.alineo + '?' + KreiMendon(trafoparametroj)
2577					).then(
2578						respondo => {
2579							if (respondo.ok) {
2580								return respondo.text();
2581							} else {
2582								return false;
2583							}
2584						}
2585					).then(
2586						rezulto => {
2587							if (rezulto) {
2588								// Prezenti surogatajn substrekojn kiel verajn substrekojn
2589								rezulto = $(rezulto.replace(/﹍/g, '_'));
2590								mesaghodiv.html('').append(rezulto);
2591								trafodiv.append(trafofermilo);
2592								if (trafopliilo) {
2593									trafodiv.append(trafopliilo);
2594								}
2595								const formuloj = rezulto.find('span.formulo.tex')
2596								if (formuloj.length) {
2597									FormuloTex(formuloj.get())
2598								}
2599							} else {
2600								mesaghodiv.html('').append($('<em class="eraro">').text('Eraro! La tekstoprenado malsukcesis. Eble mankas konekto kun la Interreto, aÅ­ eble la prenado daÅ­ris tro longe.'));
2601								trafo.removeClass('jammontras');
2602								miatrafodiv.remove();
2603								trafo.data('trafodiv', false);
2604							}
2605							folio.data('jhus_fermitaj_alineoj', false)
2606						}
2607					).catch(
2608						eraro => {
2609							CON('Eraro:', eraro);
2610							trafodiv.remove();
2611							trafo.removeClass('jammontras');
2612							trafo.data('trafodiv', false);
2613							Dialogo('Eraro! La tekstoprenado malsukcesis. Ĉu eble mankas konekto kun la Interreto?');
2614						}
2615					);
2616				}
2617			}
2618		}
2619	});
2620
2621	foliojene.on('click', 'button.kopiiligilon', async ({currentTarget}) => {
2622		const button = $(currentTarget);
2623		const urlspan = button.closest('span.ligilo').find('span.url');
2624		if (urlspan.length) {
2625			try {
2626				await navigator.clipboard.writeText(urlspan.text());
2627			} catch (err) {
2628				Dialogo('La kopiado malsukcesis. Bv. provi denove.');
2629			}
2630		}
2631	});
2632
2633	foliojene.on('click', 'button.kashi_streketojn', ({currentTarget}) => {
2634		const butono = $(currentTarget);
2635		const folio = butono.data('folio');
2636		if (folio.hasClass('kashi_streketojn')) {
2637			folio.removeClass('kashi_streketojn');
2638			butono.text('Kaŝi streketojn');
2639		} else {
2640			folio.addClass('kashi_streketojn');
2641			butono.text('Malkaŝi streketojn');
2642		}
2643	});
2644
2645	foliojene.on('click', 'span.kashi_streketojn', ({currentTarget}) => {
2646		const butono = $(currentTarget);
2647		const tekstofolio = butono.data('tekstofolio');
2648		if (tekstofolio.hasClass('kashi_streketojn')) {
2649			tekstofolio.removeClass('kashi_streketojn');
2650			butono.text('Kaŝi streketojn');
2651		} else {
2652			tekstofolio.addClass('kashi_streketojn');
2653			butono.text('Malkaŝi streketojn');
2654		}
2655	});
2656
2657	const LigilEraro = () => Dialogo('Eraro! Ne eblis krei ligilon. Ĉu eble mankas konekto kun la Interreto?');
2658
2659	foliojene.on('click', 'button.krei_ligilon', ({currentTarget}) => {
2660		const butono = $(currentTarget);
2661		Dialogo(
2662			'Ĉu krei ligilon al tiu ĉi serĉo? Tiun ligilon vi povos doni al aliaj, kiuj povos aŭtomate refari kaj vidi la rezulton de tiu ĉi serĉo.',
2663			[
2664				{teksto: 'Jes, bv. krei tian ligilon', click: () => {
2665					butono.blur();
2666					const folio = butono.data('folio');
2667					const paramemoro = folio.find('button.shanghiserchon').data('paramemoro');
2668					if (paramemoro) {
2669						let kampoj = ["serchesprimoj", "elektitaj_tekstoj", "largho", "maksimumo", "uskle", "ignorifremdajhojn", "ignorimallongigojn", "uzistreketojn", "daurigi", "kunigitekstojn", "kunigiserchojn", "inverse", "rapide", "serchesprimo"];
2670						let parametroj = {};
2671						kampoj.forEach(kampo => parametroj[kampo] = paramemoro[kampo]);
2672						KolektiMarkoDatumojn(folio, parametroj);
2673						var json_datumoj = JSON.stringify(parametroj);
2674						json_datumoj  = json_datumoj.replace(/[\u007F-\uFFFF]/g, function(chr) {
2675							return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4);
2676						});
2677						fetch(
2678							programoj.krei_ligilon, {
2679								method: 'POST',
2680								headers: {
2681									'Content-type': 'application/json'
2682								},
2683								body: JSON.stringify({data: json_datumoj})
2684							}
2685						).then(
2686							respondo => {
2687								if (respondo.ok) {
2688									return Objektigi(respondo.json());
2689								} else {
2690									return false;
2691								}
2692							}
2693						).then(
2694							rezulto => {
2695								if (rezulto && rezulto.id) {
2696									const ligilo_span = folio.data('ligilo_span');
2697									ligilo_span.find('span.ena').remove();
2698									ligilo_span.find('button.kopiiligilon').remove();
2699									const ligilo_ena_span = $('<span title="Ligilo al tiu ĉi serĉo">Ligilo: </span>');
2700									const ligilo_url_span = $(`<span class="url">https://${location.hostname}/?s=${rezulto.id}</span>`);
2701									ligilo_ena_span.append(ligilo_url_span);
2702									ligilo_span.append(ligilo_ena_span);
2703									const kopii_butono = $('<button class="kopiiligilon" title="Kopii la ligilo-adreson" data-ligilo="https://' + location.hostname + '/?s=' + rezulto.id + '">Kopii</button>');
2704									ligilo_span.addClass('kopii');
2705									ligilo_span.append(ligilo_ena_span);
2706									ligilo_span.append(kopii_butono);
2707								} else {
2708									CON('Eraro', rezulto);
2709									LigilEraro();
2710								}
2711							}
2712						).catch(
2713							eraro => {
2714								CON('Eraro', eraro);
2715								LigilEraro();
2716							}
2717						);
2718					}
2719				}},
2720				{
2721					teksto: 'Nun ne',
2722					click: () => butono.blur()
2723				}
2724			]
2725		);
2726	});
2727
2728	$(window).on('resize', () => {
2729		KashiShvebinformojn();
2730		if (tekstoadapto) {
2731			clearTimeout(tekstoadapto);
2732		}
2733		tekstoadapto = setTimeout(AdaptiChiujnTekstojn, 500);
2734	});
2735
2736	ekjaro.on('blur', () => {
2737		let ek = parseInt(ekjaro.val(), 10);
2738		const min = ekjaro.data('min');
2739		const max = ekjaro.data('max');
2740		if (ek < min) {
2741			ek = min;
2742		} else if (ek > max) {
2743			ek = max;
2744		}
2745		if (ek) {
2746			ekjaro.val(ek);
2747			finjaro.data('min', ek);
2748		} else {
2749			ekjaro.val('');
2750		}
2751	});
2752
2753	finjaro.on('blur', () => {
2754		let fin = parseInt(finjaro.val(), 10);
2755		const min = finjaro.data('min');
2756		const max = finjaro.data('max');
2757		if (fin < min) {
2758			fin = min;
2759		} else if (fin > max) {
2760			fin = max;
2761		}
2762		if (fin) {
2763			finjaro.val(fin);
2764			ekjaro.data('max', fin);
2765		} else {
2766			finjaro.val('');
2767		}
2768	});
2769
2770	ekjaro.on('keyup input', evento => {
2771		evento.stopPropagation();
2772		if (evento.key !== undefined && evento.key.length > 1) {
2773			return false;
2774		}
2775		let ek = ekjaro.val();
2776		let fin = finjaro.val();
2777		ek = ek.replace(/\D/, '');
2778		fin = fin.replace(/\D/, '');
2779		ekjaro.val(ek);
2780		finjaro.val(fin);
2781		if (ek.length !== 4 || fin.length !== 4) {
2782			return;
2783		}
2784		ek = parseInt(ek, 10) || 0;
2785		fin = parseInt(fin, 10) || 0;
2786		const min = parseInt(ekjaro.data('min'), 10);
2787		const max = parseInt(ekjaro.data('max'), 10);
2788		if (ek < min) {
2789			ek = min;
2790		} else if (ek > max) {
2791			ek = max;
2792		}
2793		ekjaro.val(ek);
2794		finjaro.data('min', ek);
2795		ElektuJare(parseInt(ek, 10), parseInt(fin, 10));
2796	});
2797
2798	finjaro.on('keyup input', evento => {
2799		evento.stopPropagation();
2800		if (evento.key !== undefined && evento.key.length > 1) {
2801			return false;
2802		}
2803		let ek = ekjaro.val();
2804		let fin = finjaro.val();
2805		ek = ek.replace(/\D/, '');
2806		fin = fin.replace(/\D/, '');
2807		ekjaro.val(ek);
2808		finjaro.val(fin);
2809		if (ek.length !== 4 || fin.length !== 4) {
2810			return;
2811		}
2812		ek = parseInt(ek, 10) || 0;
2813		fin = parseInt(fin, 10) || 0;
2814		const min = parseInt(finjaro.data('min'), 10);
2815		const max = parseInt(finjaro.data('max'), 10);
2816		if (fin < min) {
2817			fin = min;
2818		} else if (fin > max) {
2819			fin = max;
2820		}
2821		finjaro.val(fin);
2822		ekjaro.data('max', fin);
2823		ElektuJare(ek, fin);
2824	});
2825
2826	jarojaktivaj.on('change', () => {
2827		const checked = jarojaktivaj.prop('checked');
2828		ekjaro.prop('disabled', !checked);
2829		finjaro.prop('disabled', !checked);
2830		jaroj.toggleClass('aktiva', checked);
2831		body.toggleClass('jaroj', checked);
2832		la_butonoj.toggleClass('jaroj', checked);
2833		if (checked) {
2834			ekjaro.trigger('keyup');
2835		}
2836	});
2837
2838	body.on('keyup', 'input.serchesprimo', (e) => {
2839		return false;
2840	});
2841
2842	pivautoroj.on('click', () => {
2843		if (body.hasClass('jaroj')) {
2844			return;
2845		}
2846		const label = $('<label>PIV-aÅ­toroj: </label>');
2847		const inputo = $('<input class="pivautoroj" type="text" size="20" value=""/>');
2848		let pivdialogo = false;
2849		inputo.data('dialogo', pivdialogo);
2850		label.append(inputo);
2851		const enhavo = $('<div/>');
2852		enhavo.append(label);
2853		inputo.data('dialogo', Dialogo(enhavo, false, false, () => {
2854			const inputo = $('input.pivautoroj');
2855			if (inputo.length) {
2856				inputo.focus();
2857			}
2858		}));
2859	});
2860	body.on('keyup', 'input.pivautoroj', (e) => {
2861		if (e.key === 'Enter') {
2862			const inputo = $(e.currentTarget);
2863			const dialogo = inputo.data('dialogo');
2864			const val = inputo.val().trim();
2865			if (val) {
2866				const autoroj = val.split(/ +/);
2867				FermiDialogon(dialogo);
2868				if (autoroj) {
2869					$.each(autoroj, (i, a) => {
2870						if (i === 0 && a === '0') {
2871							neniuj.trigger('click');
2872						}
2873						var checkbox = $('input.PIV_' + a.toUpperCase());
2874						if (checkbox.length) {
2875							$.each(checkbox, (j, c) => {
2876								c = $(c);
2877								const div = c.closest('div.teksto.malshaltita');
2878								if (!div.length) {
2879									$(c).trigger('click');
2880								}
2881							});
2882						}
2883					});
2884				}
2885			} else {
2886				FermiDialogon(dialogo);
2887			}
2888		} else if (e.key === 'Escape') {
2889			const dialogo = inputo.data('dialogo');
2890			if (dialogo) {
2891				FermiDialogon(dialogo);
2892			}
2893		}
2894		return false;
2895	});
2896
2897	foliojene.on('click', 'div.trafolinio span.teksto', evento => {
2898		if (evento.ctrlKey) {
2899			const span = $(evento.currentTarget);
2900			MarkiTrafon(span);
2901		}
2902	});
2903
2904	// Fulmoklavoj
2905	body.on('keyup', e => {
2906		if (!fulmoklavoj_aktivaj || body.hasClass('dialogo')) {
2907			return
2908		}
2909		let klavo = e.key
2910
2911		if (['h', 'l', 'H', 'L', 'ArrowLeft' , 'ArrowRight'].includes(klavo)) {
2912			let aktiva = langetoj.find('li.aktiva')
2913			if (aktiva.length) {
2914				let celoj = langetoj.find('li:not(.forigita')
2915				let celo, trovis = false
2916				celoj.each( (i, c) => {
2917					if (c === aktiva[0]) {
2918						if (klavo === 'h' || klavo === 'H' || klavo === 'ArrowLeft') {
2919							celo = celoj[i-1]
2920						} else {
2921							celo = celoj[i+1]
2922						}
2923						if (celo) {
2924							$(celo).trigger('click')
2925						}
2926						return false
2927					}
2928				})
2929			}
2930			return
2931		}
2932
2933		if (klavo === 'X') {
2934			fermichiujn.trigger('click')
2935			return
2936		}
2937
2938		if (klavo === '!') {
2939			haltigichiujn.trigger('click')
2940			return
2941		}
2942
2943		if (serchilo_aktiva) {
2944			if (klavo === 'Enter') {
2945				priserchi.trigger('click')
2946			} else if (klavo === 's' || klavo === 'S' || klavo === 'Escape') {
2947				serchesprimoj.find('input').last().focus()
2948			} else if (klavo === '+') {
2949				aldoniserchesprimon.trigger('click');
2950			} else if (klavo === '-') {
2951				forigiserchesprimon.trigger('click');
2952			} else if (klavo === 'c' || klavo === 'C' || klavo === 'ĉ' || klavo === 'Ĉ') {
2953				chiuj.trigger('click');
2954			} else if (klavo === 'n' || klavo === 'N') {
2955				neniuj.trigger('click');
2956			} else if (klavo === 'i' || klavo === 'I') {
2957				inversigi.trigger('click');
2958			} else if (klavo === 'z' || klavo === 'Z') {
2959				zamenhofaj.trigger('click');
2960			} else if (klavo === 'm' || klavo === 'M') {
2961				montriinformojn.trigger('click');
2962			} else if (klavo === 'p' || klavo === 'P') {
2963				jarojaktivaj.trigger('click');
2964			} else if (klavo === 'f' || klavo === 'F') {
2965				ignorifremdajhojn.trigger('click');
2966			} else if (klavo === 'g' || klavo === 'G') {
2967				ignorimallongigojn.trigger('click');
2968			} else if (klavo === 'o' || klavo === 'O') {
2969				largho.focus();
2970			} else if (klavo === 't' || klavo === 'T') {
2971				maksimumo.focus();
2972			} else if (klavo === 'a' || klavo === 'A') {
2973				pivautoroj.trigger('click');
2974			} else if (klavo === 'r' || klavo === 'R') {
2975				uzistreketojn.trigger('click');
2976			} else if (klavo === 'u' || klavo === 'U') {
2977				uskle.trigger('click');
2978			} else if (klavo === 'v' || klavo === 'V') {
2979				inverse.trigger('click');
2980			} else if (klavo === 'd' || klavo === 'D') {
2981				rapide.trigger('click');
2982			}
2983		} else {
2984			if (klavo === 'x') {
2985				$('li.langeto.aktiva span.fermilo').trigger('click')
2986			} else if (klavo === 's' || klavo === 'S') {
2987				AktivigiSerchilon();
2988				serchesprimoj.find('input').last().focus()
2989			} else if (klavo === 'a' || klavo === 'A') {
2990				$('div.aktivafolio button.shanghiserchon').trigger('click')
2991			} else if (klavo === 'f' || klavo === 'F') {
2992				$('div.aktivafolio button.finiserchon').trigger('click')
2993			} else if (klavo === 'k' || klavo === 'K') {
2994				// Fermi ĉiujn malfermitajn alineojn de la serĉorezulto, aŭ - se neniu alieno estas malfermita - reaktivigi ĉiujn antaŭe fermitajn
2995				let aktiva_folio = foliojene.find('div.aktivafolio')
2996				if (aktiva_folio.length) {
2997					let trafo
2998					let miatrafodiv
2999					let jhus_fermitaj_alineoj
3000					let jammontras = aktiva_folio.find('div.trafolinio strong.trafo.jammontras')
3001					if (jammontras.length) {
3002						jhus_fermitaj_alineoj = []
3003						jammontras.each( function(i, trafo) {
3004							trafo = $(trafo)
3005							miatrafodiv = trafo.data('trafodiv');
3006							if (miatrafodiv && miatrafodiv.length && !miatrafodiv.hasClass('kashita')) {
3007								miatrafodiv.addClass('kashita')
3008								jhus_fermitaj_alineoj.push(miatrafodiv)
3009							}
3010						})
3011						if (jhus_fermitaj_alineoj.length) {
3012							aktiva_folio.data('jhus_fermitaj_alineoj', jhus_fermitaj_alineoj)
3013						} else {
3014							jhus_fermitaj_alineoj = aktiva_folio.data('jhus_fermitaj_alineoj')
3015							if (jhus_fermitaj_alineoj && jhus_fermitaj_alineoj.length) {
3016								$.each(jhus_fermitaj_alineoj, function(i, alineo) {
3017									$(alineo).removeClass('kashita')
3018								})
3019							}
3020						}
3021					}
3022				}
3023			}
3024		}
3025	})
3026
3027	const Trafohoko = (inputo, fini) => {
3028		const linio = inputo.data('linio');
3029		const trafo = inputo.data('trafo');
3030		let trafodiv;
3031		if (trafo) {
3032			trafodiv = trafo.data('trafodiv');
3033		}
3034		if (inputo.prop('checked')) {
3035			linio.addClass('markita');
3036			if (trafodiv) {
3037				trafodiv.addClass('markita');
3038			}
3039		} else {
3040			linio.removeClass('markita');
3041			if (trafodiv) {
3042				trafodiv.removeClass('markita');
3043			}
3044		}
3045		if (fini) {
3046			const folio = inputo.data('folio');
3047			if (folio) {
3048				KontroliMarkitajn(folio);
3049				let speco;
3050				if (folio.hasClass('kashimarkitajn')) {
3051					speco = 'markitaj';
3052				} else if (folio.hasClass('kashinemarkitajn')) {
3053					speco = 'nemarkitaj';
3054				} else {
3055					speco = 'malkashi';
3056				}
3057				KontroliTrafoSekciojn(folio, speco);
3058			}
3059		}
3060	};
3061
3062	const KontroliSekcion = sekcihoko => {
3063		const sekcio = sekcihoko.data('serchoprezento');
3064		const markitaj = sekcio.find('input.trafohoko:checked');
3065		const nemarkitaj = sekcio.find('input.trafohoko:not(:checked)');
3066		if (nemarkitaj.length) {
3067			sekcihoko.prop('checked', false);
3068		} else if (markitaj.length) {
3069			sekcihoko.prop('checked', true);
3070		}
3071	};
3072
3073	const RemontriKreiLigilon = folio => {
3074		folio.data('ligilo_span').removeClass('kopii');
3075	};
3076
3077	foliojene.on('click', 'span.titolenhavo', evento => {
3078		if (evento.ctrlKey) {
3079			const titolo = $(evento.currentTarget);
3080			const sekcihoko = titolo.data('sekcihoko');
3081			if (sekcihoko) {
3082				sekcihoko.trigger('click');
3083			}
3084		}
3085	});
3086
3087	const AvertoTeksto = function(folio, reghimo) {
3088		const kashaverto = folio.data('kashaverto')
3089
3090		const kashitaj = folio.find('div.trafolinio.markita')
3091		let kashofinajho = 'j'
3092		if (kashitaj.length === 1) {
3093			kashofinajho = ''
3094		}
3095
3096		const markitaj = folio.find('div.trafolinio.markita')
3097		let markofinajho = 'j'
3098		if (markitaj.length === 1) {
3099			markofinajho = ''
3100		}
3101
3102		const nemarkitaj = folio.find('div.trafolinio:not(.markita)')
3103		let nemarkofinajho = 'j'
3104		if (nemarkitaj.length === 1) {
3105			nemarkofinajho = ''
3106		}
3107
3108		kashaverto.data('reghimo', reghimo)
3109
3110		if (reghimo === 'kashimarkitajn') {
3111			kashaverto.text(kashitaj.length + ' markita' + kashofinajho + ' trafo' + kashofinajho + ' estas kaŝita' + kashofinajho);
3112		} else if (reghimo === 'kashinemarkitajn') {
3113			kashaverto.text(nemarkitaj.length + ' nemarkita' + nemarkofinajho + ' trafo' + nemarkofinajho + ' estas kaŝita' + nemarkofinajho + ' - ' + markitaj.length + ' estas markita' + markofinajho);
3114		} else if (reghimo === 'malkashikashitajn') {
3115			if (kashitaj.length) {
3116				kashaverto.text(kashitaj.length + ' trafo' + markofinajho + ' estas markita' + markofinajho + ' - ' + nemarkitaj.length + ' trafo' + nemarkofinajho + ' estas nemarkita' + nemarkofinajho);
3117			} else {
3118				kashaverto.text('');
3119			}
3120		}
3121
3122	}
3123
3124	foliojene.on('change', 'input.trafohokosekcia', ({currentTarget}) => {
3125		const inputo = $(currentTarget);
3126		const sekcio = inputo.data('serchoprezento');
3127		const checked = inputo.prop('checked');
3128		const hokoj = sekcio.find('input.trafohoko');
3129		if (hokoj.length) {
3130			hokoj.each( (indekso, inputo) => {
3131				inputo = $(inputo);
3132				inputo.prop('checked', checked);
3133				if (indekso === hokoj.length-1) {
3134					Trafohoko($(inputo), true);
3135				} else {
3136					Trafohoko($(inputo), false);
3137				}
3138			});
3139		}
3140		const folio = inputo.data('folio');
3141		const kashaverto = folio.data('kashaverto')
3142		const reghimo = kashaverto.data('reghimo') || 'malkashikashitajn'
3143		if (reghimo) {
3144			AvertoTeksto(folio, reghimo)
3145		}
3146		RemontriKreiLigilon(folio);
3147		KontroliChuMarkoj(folio);
3148	});
3149
3150	foliojene.on('change', 'input.trafohoko', ({currentTarget}) => {
3151		const inputo = $(currentTarget);
3152		Trafohoko(inputo, true);
3153		const sekcihoko = inputo.data('sekcihoko');
3154		KontroliSekcion(sekcihoko);
3155		const folio = inputo.data('folio');
3156		const kashaverto = folio.data('kashaverto')
3157		const reghimo = kashaverto.data('reghimo') || 'malkashikashitajn'
3158		if (reghimo) {
3159			AvertoTeksto(folio, reghimo)
3160		}
3161		RemontriKreiLigilon(folio);
3162		KontroliChuMarkoj(folio);
3163	});
3164
3165	foliojene.on('click', 'span.kashimarkitajn', ({currentTarget}) => {
3166		const butono = $(currentTarget);
3167		const folio = butono.data('folio');
3168		folio.removeClass('kashinemarkitajn');
3169		folio.addClass('kashimarkitajn');
3170		AvertoTeksto(folio, 'kashimarkitajn')
3171		KonserviSerchilostaton();
3172		KontroliTrafoSekciojn(folio, 'markitaj');
3173		RemontriKreiLigilon(folio);
3174	});
3175
3176	foliojene.on('click', 'span.kashinemarkitajn', ({currentTarget}) => {
3177		const butono = $(currentTarget);
3178		const folio = butono.data('folio');
3179		folio.removeClass('kashimarkitajn');
3180		folio.addClass('kashinemarkitajn');
3181		AvertoTeksto(folio, 'kashinemarkitajn')
3182		KonserviSerchilostaton();
3183		KontroliTrafoSekciojn(folio, 'nemarkitaj');
3184		RemontriKreiLigilon(folio);
3185	});
3186
3187	foliojene.on('click', 'span.malkashikashitajn', ({currentTarget}) => {
3188		const butono = $(currentTarget);
3189		const folio = butono.data('folio');
3190		folio.removeClass('kashimarkitajn');
3191		folio.removeClass('kashinemarkitajn');
3192		AvertoTeksto(folio, 'malkashikashitajn')
3193		KonserviSerchilostaton();
3194		KontroliTrafoSekciojn(folio, 'malkashi');
3195		RemontriKreiLigilon(folio);
3196	});
3197
3198	foliojene.on('click', 'span.forigimarkojn', ({currentTarget}) => {
3199		const butono = $(currentTarget);
3200		const folio = butono.data('folio');
3201		const averto = folio.data('kashaverto')
3202		AvertoTeksto(folio, 'forigimarkojn')
3203		folio.find('input.trafohokosekcia').each( (indekso, sekcihoko) => {
3204			sekcihoko = $(sekcihoko);
3205			sekcihoko.prop('checked', false).trigger('change');
3206			folio.find('span.malkashikashitajn').trigger('click');
3207		});
3208	});
3209
3210	let tekstoj_php_para = '?v=' + VERSIO;
3211	if (url_id) {
3212		tekstoj_php_para += '&url_id=' + url_id;
3213	}
3214	fetch(
3215		programoj.tekstolisto + tekstoj_php_para
3216	).then(
3217		respondo => {
3218			if (respondo.ok) {
3219				return Objektigi(respondo.json());
3220			} else {
3221				return false;
3222			}
3223		}
3224	).then(
3225		rezulto => {
3226			if (rezulto) {
3227				if (LOKE && rezulto.skriborezulto === 0) {
3228					Dialogo(
3229						'Ne eblis ĝisdatigi “tekstoj.json”'
3230					);
3231				}
3232				const latekstoj = Objektigi(JSON.parse(rezulto.latekstoj));
3233				var dokumentofragmento = document.createDocumentFragment();
3234				Object.keys(latekstoj).forEach( nomo => {
3235					const t = latekstoj[nomo];
3236					if (!laekjaro || t.nurajaro < laekjaro) {
3237						laekjaro = t.nurajaro;
3238					}
3239					if (!lafinjaro || t.nurajaro > lafinjaro) {
3240						lafinjaro = t.nurajaro;
3241					}
3242					const teksto_div = $(`<div id="teksto_${t.nomo}" class="teksto ${t.z}"/>`);
3243					teksto_div.data('jaro', t.nurajaro).data('data', t);
3244					if (t.protektita && t.protektita === 1) {
3245						teksto_div.append($('<div class="montri protektita">!</div>').attr('title', `La teksto de “${t.titolo}” ne rajtas esti plene montrata`));
3246					} else {
3247						teksto_div.append($('<div class="montri">M</div>').attr('title', `Montri/malŝalti la tekston de “${t.titolo}”`));
3248					}
3249					const c_input = $('<input type="checkbox"/>');
3250					const c_div = $('<div class="check"/>');
3251					if (t.piv) {
3252						c_input.addClass('PIV_' + t.piv.join(' PIV_'));
3253					}
3254					c_div.append(c_input);
3255					teksto_div.append(c_div);
3256					const nomo_div = $('<div class="nomo"/>');
3257					const nomo_label = $('<span class="label"/>');
3258					const nomo_cite = $('<cite/>');
3259					nomo_cite.append(document.createTextNode(t.titolo));
3260					if (t.titolo.indexOf(t.jaro) === -1) {
3261						nomo_cite.append(document.createTextNode('\u00a0'));
3262						nomo_cite.append($('<em>').text(t.jaro.replace(/-/, '‑')));
3263						nomo_cite.append(document.createTextNode('\u00a0'));
3264					}
3265					if (t.z.match(/^z/)) {
3266						nomo_cite.append(document.createTextNode('\u00a0'));
3267						let ztitolo = 'Zamenhofa teksto', zsimbolo = 'Z';
3268						if (t.z === 'z r') {
3269							ztitolo += ' reviziita';
3270							zsimbolo = '(Z)';
3271						}
3272						nomo_cite.append($(`<span class="Z" title="${ztitolo}">${zsimbolo}</span>`));
3273					}
3274					const informoj_span = $('<span class="informoj"/>');
3275					const informoj_arr = [];
3276					if (t.subtitolo) {
3277						informoj_arr.push(InformoLinio('Subtitolo', t.subtitolo));
3278					}
3279					if (t.plumis) {
3280						informoj_arr.push(InformoLinio('E-a teksto', t.plumis));
3281					}
3282					if (t.jaro) {
3283						informoj_arr.push(InformoLinio('Jaro', t.jaro));
3284					}
3285					if (t.presloko) {
3286						informoj_arr.push(InformoLinio('Eldonado', t.presloko));
3287					}
3288					if (t.grando) {
3289						informoj_arr.push(InformoLinio('Longo', t.grando + ' vortoj'));
3290					}
3291					const longo = informoj_arr.length - 1;
3292					informoj_arr.forEach( (span, indekso) => {
3293						informoj_span.append(span);
3294						if (indekso < longo) {
3295							informoj_span.append(document.createTextNode(' '));
3296						}
3297					});
3298					nomo_label.append(nomo_cite).append(informoj_span);
3299					nomo_div.append(nomo_label);
3300					teksto_div.append(nomo_div);
3301					teksto_div.appendTo(dokumentofragmento);
3302				});
3303				tekstoj.append(dokumentofragmento);
3304				chiuj_tekstoj = tekstoj.find('div.teksto');
3305				ekjaro.data('min', laekjaro);
3306				ekjaro.data('max', lafinjaro);
3307				finjaro.data('min', laekjaro);
3308				finjaro.data('max', lafinjaro);
3309
3310				if (!LOKE) {
3311					KontroliVersion();
3312				}
3313			}
3314			return rezulto.url_sercho;
3315		}
3316	).then(
3317		url_sercho => {
3318			let para;
3319			if (url_sercho) {
3320				try {
3321					para = $.parseJSON(url_sercho);
3322				} catch(e) {
3323					CON('url_sercho-eraro', e);
3324				}
3325			}
3326			body.addClass('shargita');
3327			IgiRegrandigebla(serchesprimoj);
3328			if (para) {
3329				RestarigiSerchilostaton(para);
3330			} else if (stato) {
3331				RestarigiSerchilostaton(stato);
3332			}
3333			iloj.find('input[type=checkbox]').each( (index, obj) => {
3334				const input = $(obj);
3335				if (input.prop('checked')) {
3336					input.closest('label').addClass('checked');
3337				} else {
3338					input.closest('label').removeClass('checked');
3339				}
3340			});
3341			formularo.on('change', function(e) {
3342				KonserviSerchilostaton();
3343			})
3344			KonserviSerchilostaton();
3345			ReghustigiSerchesprimojn();
3346			if (para) {
3347				priserchi.trigger('click')
3348			}
3349		}
3350	).catch(
3351		eraro => {
3352			CON('Eraro', eraro);
3353		}
3354	);
3355};

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.