PageSourceSearch

https://sprotin.fo/site/templates/default/assets/javascripts/fm.dictionary.jquery.js?v=3.28b.5-20

js sprotin.fo collected 2026-10-02 07:03:59 UTC 103,842 bytes, 2,483 lines download raw bytes

1var Dictionary = {
2	/** Reference to the virtual keyboard */
3	virtualKeyboard: null,
4
5	/** The container for the return data */
6	searchData: {},
7
8	/** Initialize the dictionary buttons, actions and events */
9	Init: function () {
10		// Initialize virtual keyboard
11		var $dictionaryControls = $('.dictionary-controls--component');
12		var $dictionaryInput = $('.dictionary-input--component');
13		var $dictionaryInputTextbox = $dictionaryInput.find('.dictionary-input--textbox');
14		var $virtualKeyboard = $('.virtual-keyboard--component');
15		var $virtualKeyboardKeys = $virtualKeyboard.find('.virtual-keyboard--keys');
16		Dictionary.virtualKeyboard = new VirtualKeyboard($virtualKeyboardKeys, $dictionaryInputTextbox);
17		Dictionary.virtualKeyboard.onreturnpress = function () {
18			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_DictionaryPage,_WordId,_Group') + '&_DictionaryPage=1&_SearchFor=' + $dictionaryInputTextbox.val());
19			$dictionaryInputTextbox.autocomplete('clearSearchResults');
20			Dictionary.Search(0, 0, false, true);
21		};
22		Dictionary.virtualKeyboard.refreshLayout();
23
24		// Bind events
25		Dictionary.BindEvents();
26
27		// Do initial search
28		Dictionary.Search(0, 0, false, true);
29
30		Dictionary.Spellchecker.Init();
31	},
32
33	/** Bind all dictionary control and search_results events */
34	BindEvents: function () {
35		var $dictionaryControls = $('.dictionary-controls--component');
36		var $dictionaryInput = $('.dictionary-input--component');
37		var $dictionaryInputTextbox = $dictionaryInput.find('.dictionary-input--textbox');
38		var $dictionarySelector = $('.dictionary-selector--component');
39		var $dictionarySendSuggestion = $('.dictionary-send-suggestion--component');
40		var $dictionarySpellchecker = $('.dictionary-spellchecker--component');
41		var $dictionaryResults = $('.dictionary-results--component');
42		var $virtualKeyboard = $('.virtual-keyboard--component');
43		// Bind window popstate event
44		window.onpopstate = function() {
45			Dictionary.Search(0, 0, false, true);
46		};
47		// Bind history previous button event
48		$dictionaryControls.find('.dictionary-controls--button--back').on('click', function () {
49			window.history.back();
50		});
51		// Bind history next button event
52		$dictionaryControls.find('.dictionary-controls--button--forward').on('click', function () {
53			window.history.forward();
54		});
55		// Bind special character inserter events
56		$dictionaryControls.find('.dictionary-controls--character').on('click', function () {
57			var character = $(this).attr('data-letter');
58			$dictionaryInputTextbox.insertAtCaret(character);
59		});
60		// Bind virtual keyboard toggle event
61		$dictionaryControls.find('.dictionary-input--virtual-keyboard-icon').on('click', function () {
62			if (!$virtualKeyboard.hasClass('virtual-keyboard--visible')) {
63				$virtualKeyboard.addClass('virtual-keyboard--visible').slideDown(300);
64				$(this).addClass('dictionary-input--virtual-keyboard-icon--active');
65			} else {
66				$virtualKeyboard.removeClass('virtual-keyboard--visible').slideUp(300);
67				$(this).removeClass('dictionary-input--virtual-keyboard-icon--active');
68			}
69		});
70		// Bind virtual keyboard language selecters events
71		$virtualKeyboard.find('.virtual-keyboard--languages').find('.virtual-keyboard--language').on('click', function () {
72			var language = $(this).attr('data-language');
73			$virtualKeyboard.find('.virtual-keyboard--language').each(function () {
74				$(this).removeClass('virtual-keyboard--language--active');
75				if ($(this).attr('data-language') === language) {
76					$(this).addClass('virtual-keyboard--language--active');
77				}
78			});
79			console.log(language);
80			Dictionary.virtualKeyboard.changeLanguage(language);
81		});
82		// Bind search in inflections toggle event
83		$dictionaryControls.find('.dictionary-controls--button--search-inflections').on('click', function () {
84			history.pushState(null, '', '?' + Tools.getQuery('_SearchInflections,_SearchDescriptions,_WordId') + '&_SearchDescriptions=0&_SearchInflections=' + (Tools.getQueryVariable('_SearchInflections') === '1' ? '0' : '1'));
85			Dictionary.Search(0, 0, false, true);
86		});
87		// Bind search in description toggle event
88		$dictionaryControls.find('.dictionary-controls--button--search-description').on('click', function () {
89			history.pushState(null, '', '?' + Tools.getQuery('_SearchDescriptions,_SearchInflections,_WordId') + '&_SearchInflections=0&_SearchDescriptions=' + (Tools.getQueryVariable('_SearchDescriptions') === '1' ? '0' : '1'));
90			Dictionary.Search(0, 0, false, true);
91		});
92		// Bind larger font toggle
93		$dictionaryControls.find('.dictionary-controls--font-size').on('click', function () {
94			var $this = $(this);
95			if (!$this.hasClass('dictionary-controls--button--active')) {
96				$this.addClass('dictionary-controls--button--active');
97				$dictionaryResults.addClass('dictionary-results--component--largertext');
98			} else {
99				$this.removeClass('dictionary-controls--button--active');
100				$dictionaryResults.removeClass('dictionary-results--component--largertext');
101			}
102		});
103		// Bind send suggestion toggle
104		$dictionaryControls.find('.dictionary-controls--send-suggestion').on('click', function () {
105			var $this = $(this);
106			if (!$this.hasClass('dictionary-controls--button--active')) {
107				$this.addClass('dictionary-controls--button--active');
108				$dictionaryControls.find('.dictionary-controls--spellchecker').removeClass('dictionary-controls--button--active');
109				$dictionaryResults.slideUp();
110				$dictionarySendSuggestion.slideDown();
111				$dictionarySpellchecker.slideUp();
112				//$dictionaryResults.addClass('dictionary-results--component--send-suggestion');
113			} else {
114				$this.removeClass('dictionary-controls--button--active');
115				$dictionaryResults.slideDown();
116				$dictionarySendSuggestion.slideUp();
117				$dictionarySpellchecker.slideUp();
118				//$dictionaryResults.removeClass('dictionary-results--component--send-suggestion');
119			}
120		});
121		// Bind submit suggestion
122		$dictionarySendSuggestion.find('.dictionary-send-suggestion--form').on('submit', function (e) {
123			var $form= $(this);
124			e.preventDefault();
125			if (!$dictionarySendSuggestion.find('.dictionary-send-suggestion--submit').hasClass('busy')) {
126				if (Validator.validate($form)) {
127					$dictionarySendSuggestion.find('.dictionary-send-suggestion--submit').addClass('busy');
128					$.post('/dictionary_suggestion_do.php', $form.serialize(), function () {
129						$dictionarySendSuggestion.find('.dictionary-send-suggestion--self').slideUp(function () {
130							$form[0].reset();
131							$dictionarySendSuggestion.find('.dictionary-send-suggestion--submit').removeClass('busy');
132						});
133						$dictionarySendSuggestion.find('.dictionary-send-suggestion--confirmation').slideDown();
134					});
135				}
136			}
137		});
138		// Close "send suggestion" confirmation
139		$dictionarySendSuggestion.find('.dictionary-send-suggestion--close-button').on('click', function () {
140			$dictionaryControls.find('.dictionary-controls--send-suggestion').removeClass('dictionary-controls--button--active');
141			$dictionaryResults.slideDown();
142			$dictionarySendSuggestion.slideUp(function () {
143				$dictionarySendSuggestion.find('.dictionary-send-suggestion--self').show();
144				$dictionarySendSuggestion.find('.dictionary-send-suggestion--confirmation').hide();
145			});
146		});
147		// Bind spellchecker toggle
148		$dictionaryControls.find('.dictionary-controls--spellchecker').on('click', function () {
149			var $this = $(this);
150			if (!$this.hasClass('dictionary-controls--button--active')) {
151				$this.addClass('dictionary-controls--button--active');
152				$dictionaryControls.find('.dictionary-controls--send-suggestion').removeClass('dictionary-controls--button--active');
153				$dictionaryResults.slideUp();
154				$dictionarySendSuggestion.slideUp();
155				$dictionarySpellchecker.slideDown();
156				//$dictionaryResults.addClass('dictionary-results--component--spellchecker');
157			} else {
158				$this.removeClass('dictionary-controls--button--active');
159				$dictionaryResults.slideDown();
160				$dictionarySendSuggestion.slideUp();
161				$dictionarySpellchecker.slideUp();
162				//$dictionaryResults.removeClass('dictionary-results--component--spellchecker');
163			}
164		});
165		// Bind searchbox autocomplete events
166		$dictionaryInputTextbox.autocomplete({
167			item_url: '/dictionaries?l=' + Ease.siteLanguage + '&',
168			item_param: '_SearchFor',
169			search_url: '',
170			results_class: 'dictionaries-autocomplete--component',
171			results_item_class: 'dictionaries-autocomplete--item',
172			results_item_active_class: 'dictionaries-autocomplete--item--active',
173			results_item_text_class: 'dictionaries-autocomplete--text',
174			results_item_type_class: 'dictionaries-autocomplete--type',
175			results_message_class: 'dictionaries-autocomplete--message',
176			url: '/dictionary_autocomplete_json.php',
177			search_callback: function (e, searchFor) {
178				history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_DictionaryPage,_WordId,_Group') + '&_DictionaryPage=1&_SearchFor=' + searchFor);
179				$dictionaryInputTextbox.autocomplete('clearSearchResults');
180				Dictionary.Search(0, 0, false, true);
181			},
182			item_select_callback: function (e, focusedSearchResult) {
183				$dictionaryInputTextbox.val(focusedSearchResult.Id);
184				history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_DictionaryPage,_WordId,_Group') + '&_DictionaryPage=1&_SearchFor=' + focusedSearchResult.Id);
185				$dictionaryInputTextbox.autocomplete('clearSearchResults');
186				Dictionary.Search(0, 0, false, true);
187			},
188			extra_params_callback: function () {
189				return {
190					'DictionaryId': Tools.getQueryVariable('_DictionaryId'),
191					'SearchInflections': Tools.getQueryVariable('_SearchInflections'),
192					'SearchDescriptions': Tools.getQueryVariable('_SearchDescriptions'),
193					'Group': Tools.getQueryVariable('_Group')
194				};
195			},
196			param: 'SearchFor'
197		});
198		// Bind standard submit event from searchbox
199		$dictionaryInput.find('.dictionary-input--search-icon').on('click', function (e) {
200			e.preventDefault();
201			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $dictionaryInputTextbox.val());
202			Dictionary.Search(0, 0, true, true);
203		});
204		// Bind standard submit event from searchbox
205		$dictionaryInput.find('.dictionary-input--form').on('submit', function (e) {
206			e.preventDefault();
207			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $dictionaryInputTextbox.val());
208			Dictionary.Search(0, 0, false, true);
209		});
210		// Bind reset button
211		$dictionaryInput.find('.dictionary-input--reset-icon').on('click', function (e) {
212			e.preventDefault();
213			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=');
214			Dictionary.Search(0, 0, false, true);
215			$dictionaryInputTextbox.autocomplete('clearSearchResults');
216			$dictionaryInputTextbox.focus();
217		});
218		// Bind dictionary selectors events
219		$dictionarySelector.find('.dictionary-selector--item').on('click', function () {
220			var dictionaryId = $(this).attr('data-id');
221			history.pushState(null, '', '?' + Tools.getQuery('_DictionaryId,_DictionaryPage,_Group,_WordId') + '&_DictionaryPage=1&_DictionaryId=' + dictionaryId + '&_Group=');
222			$dictionaryInputTextbox.autocomplete('clearSearchResults');
223			Dictionary.Search(0, 0, false, true);
224			$dictionaryInputTextbox.autocomplete('clearSearchResults');
225		});
226		// Bind words suggestions click event
227		$dictionaryResults.on('click', '.dictionary-results--not-found-suggestions-item', function () {
228			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $(this).attr('data-searchword'));
229			Dictionary.Search(0, 0, false, true);
230		});
231		// Bind previous page arrow
232		$dictionaryResults.on('click', '.dictionary-results--pager-item--previous', function () {
233			Dictionary.Page('previous');
234			Dictionary.Search(1, 1, false, true);
235		});
236		// Bind next page arrow
237		$dictionaryResults.on('click', '.dictionary-results--pager-item--next', function () {
238			Dictionary.Page('next');
239			Dictionary.Search(1, 1, false, true);
240		});
241		// Bind word Inflections icon
242		$dictionaryResults.on('click', '.dictionary-results--word-icon--inflectedform', function () {
243			var $this = $(this);
244			if ($this.attr('data-dictionary-table') !== 'fr-fo') {
245				Dictionary.Inflection.Toggle($this.attr('data-word-id'));
246			} else {
247				var win = window.open('https://leconjugueur.lefigaro.fr/conjugaison/verbe/' + escape($(this).attr('data-searchword')) + '.html', '_blank');
248				win.focus();
249			}
250		});
251		// Bind word Audio icon (readspeaker)
252		$dictionaryResults.on('click', '.dictionary-results--word-icon--audio', function (e) {
253			var $this = $(this);
254			e.preventDefault();
255			e.stopPropagation();
256			$dictionaryResults.find('.dictionary-results--word-icon--audio.dictionary-results--word-icon--active').removeClass('dictionary-results--word-icon--active');
257			$this.addClass('dictionary-results--word-icon--active');
258			Dictionary.ReadText($this.attr('data-text'), $this.attr('data-language'));
259		});
260		// Bind readspeaker element change event
261		observeDOM('#readspeaker1', {
262			mutationlistener: {
263				attributes: true,
264				attributeFilter: ['class']
265			}
266		}, function () {
267			if ($('#readspeaker1').hasClass('rsstopped')) {
268				$dictionaryResults.find('.dictionary-results--word-icon--audio.dictionary-results--word-icon--active').removeClass('dictionary-results--word-icon--active');
269			}
270		});
271		// Bind word Origin icon
272		$dictionaryResults.on('click', '.dictionary-results--word-icon--origin', function () {
273			var $this = $(this);
274			Dictionary.Origin.Toggle($this.attr('data-word-id'));
275		});
276		// Bind word Share icon
277		$dictionaryResults.on('click', '.dictionary-results--word-icon--share', function () {
278			var $this = $(this);
279			Dictionary.Share.Toggle($this.attr('data-word-id'));
280		});
281		// Bind word Feedback icon
282		$dictionaryResults.on('click', '.dictionary-results--word-icon--feedback', function () {
283			var $this = $(this);
284			Dictionary.Feedback.Toggle($this.attr('data-word-id'));
285		});
286		// Bind word-link event listerner
287		$dictionaryResults.on('click', '.dictionary-results--word-link', function () {
288			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $(this).attr('data-searchfor'));
289			Dictionary.Search(0, 0, false, true);
290		});
291		// Bind word-group event listener
292		$dictionaryResults.on('click', '.dictionary-results--word-group', function (e) {
293			e.stopPropagation();
294			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_Group,_WordId,_SearchDescriptions') + '&_SearchFor=&_SearchDescriptions=0&_Group=' + $(this).attr('data-group-id'));
295			Dictionary.Search(0, 0, false, true);
296		});
297		// Bind word-group event listener
298		$dictionaryResults.on('click', '.dictionary-results--words-from-same-groups-title-group', function (e) {
299			e.stopPropagation();
300			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_Group,_WordId,_SearchDescriptions') + '&_SearchFor=&_SearchDescriptions=0&_Group=' + $(this).attr('data-group-id'));
301			Dictionary.Search(0, 0, false, true);
302		});
303		// Bind word-card event listener
304		$dictionaryResults.on('click', '.dictionary-results--word--card', function (e) {
305			if ($(this).hasClass('dictionary-results--word--single-word')) {
306				return
307			}
308			history.pushState(null, '', '?' + Tools.getQuery('_DictionaryPage,_SearchFor,_Group,_WordId,_SearchInflections,_SearchDescriptions') + '&_SearchInflections=0&_SearchDescriptions=0&_DictionaryPage=1&_Group=&_SearchFor=' + $(this).attr('data-word-searchword') + '&_WordId=' + $(this).attr('data-word-id'));
309			Dictionary.Search(0, 0, false, true);
310		});
311
312
313		// Bind similar words list toggle event
314		/*var $section_similar_words = $('#section_similar_words');
315		var $section_similar_words_list = $section_similar_words.find('.list');
316		$section_similar_words.children('.title').on('click', function () {
317			$section_similar_words_list.slideToggle();
318		});*/
319
320		// Bind similar words click event
321		/*$section_similar_words.on('click', '.item > a', function () {
322			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $(this).attr('data-searchword'));
323			Dictionary.Search(0, 0, false, true);
324		});*/
325
326		// Bind about dictionary toggle event
327		var $dictionaryAboutDictionary = $('.dictionary-about-dictionary--component');
328		var $dictionaryAboutDictionaryContent = $dictionaryAboutDictionary.find('.dictionary-about-dictionary--content');
329		$dictionaryAboutDictionary.find('.dictionary-about-dictionary--title').on('click', function () {
330			$dictionaryAboutDictionaryContent.slideToggle();
331		});
332
333		// Bind recent words list toggle event
334		var $dictionaryRecentWords = $('.dictionary-recent-words--component');
335		var $dictionaryRecentWordsContent = $dictionaryRecentWords.find('.dictionary-recent-words--content');
336		$dictionaryRecentWords.find('.dictionary-recent-words--title').on('click', function () {
337			$dictionaryRecentWordsContent.slideToggle();
338		});
339		// Bind recent words click event
340		$dictionaryRecentWords.on('click', '.dictionary-recent-words--link', function () {
341			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $(this).attr('data-searchword'));
342			Dictionary.Search(0, 0, false, true);
343		});
344		// Bind recent words load more event
345		$dictionaryRecentWords.find('.dictionary-recent-words--more').on('click', function () {
346			Dictionary.RecentWords.LoadMore();
347		});
348
349		// Bind popular words list toggle event
350		var $dictionaryPopularWords = $('.dictionary-popular-words--component');
351		var $dictionaryPopularWordsContent = $dictionaryPopularWords.find('.dictionary-popular-words--content');
352		$dictionaryPopularWords.find('.dictionary-popular-words--title').on('click', function () {
353			$dictionaryPopularWordsContent.slideToggle();
354		});
355		// Bind popular words click event
356		$dictionaryPopularWords.on('click', '.dictionary-popular-words--link', function () {
357			history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=' + $(this).attr('data-searchfor'));
358			Dictionary.Search(0, 0, false, true);
359		});
360
361		// Bind searches by country list toggle event
362		var $dictionarySearchesByCountry = $('.dictionary-searches-by-country--component');
363		var $dictionarySearchesByCountryContent = $dictionarySearchesByCountry.find('.dictionary-searches-by-country--content');
364		$dictionarySearchesByCountry.find('.dictionary-searches-by-country--title').on('click', function () {
365			$dictionarySearchesByCountryContent.slideToggle();
366		});
367	},
368
369	/** Refresh search description toggle, search inflections toggle, searchbox text and dictionary selectors */
370	RefreshControls: function () {
371
372		// Refresh search inflections toggle
373		var $buttonSearchInflections = $('.dictionary-controls--button--search-inflections');
374		if (Tools.getQueryVariable('_SearchInflections') === '1') {
375			$buttonSearchInflections.addClass('dictionary-controls--button--active');
376		} else {
377			$buttonSearchInflections.removeClass('dictionary-controls--button--active');
378		}
379
380		// Refresh search descriptions toggle
381		var $buttonSearchDescriptions = $('.dictionary-controls--button--search-description');
382		if (Tools.getQueryVariable('_SearchDescriptions') === '1') {
383			$buttonSearchDescriptions.addClass('dictionary-controls--button--active');
384		} else {
385			$buttonSearchDescriptions.removeClass('dictionary-controls--button--active');
386		}
387
388		// Refresh searchbox text
389		var $dictionaryInputTextbox = $('.dictionary-input--textbox');
390		$dictionaryInputTextbox.val(Tools.getQueryVariable('_SearchFor'));
391
392		// Refresh dictionary selectors
393		var $dictionarySelectors = $('.dictionary-selector--component');
394		$dictionarySelectors.find('.dictionary-selector--item').each(function () {
395			$(this).removeClass('dictionary-selector--item--active');
396			if ($(this).attr('data-id') === Tools.getQueryVariable('_DictionaryId')) {
397				$(this).addClass('dictionary-selector--item--active');
398			}
399		});
400
401		// Refresh groups selector
402		var $dictionaryGroupSelector = $('.dictionary-results--group-selector');
403		$dictionaryGroupSelector.val(Tools.getQueryVariable('_Group'));
404
405	},
406
407	RecentWords: {
408		Refresh: function (_clearWords, _keepRange) {
409			_clearWords = _clearWords === undefined ? 1 : (_clearWords ? 1 : 0);
410			_keepRange = _keepRange === undefined ? 0 : (_keepRange ? 1 : 0);
411			var $component = $('.dictionary-recent-words--component');
412			var $list = $component.find('.dictionary-recent-words--list');
413			var $message = $component.find('.dictionary-recent-words--message');
414			var $actions = $component.find('.dictionary-recent-words--actions');
415			var dictionaryId = Tools.getQueryVariable('_DictionaryId');
416			var offset = _clearWords && !_keepRange ? 0 : $list.children().length;
417			$.get('dictionary_recent_words_json.php', {
418				'Offset':       offset,
419				'KeepRange':    _keepRange ,
420				'DictionaryId': dictionaryId
421			}, function (data) {
422				if (_clearWords) {
423					$list.empty();
424				}
425				if (data.status !== undefined && data.status === 'annualupdates') {
426					// If dictionary is annuallyupdated show message
427					$message.html($message.attr('data-template').replace(new RegExp('{dictionary}', 'g'), data.dictionary.shortTitle));
428					$message.slideDown();
429					$actions.slideUp();
430					$list.slideUp();
431
432				} else {
433					// Populate list with recent words
434					if (data.words !== undefined) {
435						for (var i = 0; i < data.words.length; i++) {
436							var word_data = data.words[i];
437							var $word_holder = $(document.createElement('li'))
438								.addClass('dictionary-recent-words--item');
439							var $word = $(document.createElement('a'))
440								.addClass('dictionary-recent-words--link')
441								.attr('data-searchword', word_data.searchWord);
442							var $text = $(document.createElement('div'))
443								.addClass('dictionary-recent-words--text')
444								.attr('title', word_data.displayWord.replace('"', '\\"'))
445								.html(word_data.displayWord);
446							var $date = $(document.createElement('div'))
447								.addClass('dictionary-recent-words--date')
448								.html((new Date(word_data.date.replace(/-/g, '/')).toDateDDMMYYYY('.')));
449							$word.append($date);
450							$word.append($text);
451							$word_holder.append($word);
452							$list.append($word_holder);
453						}
454						$message.slideUp();
455						$list.slideDown();
456					}
457					var items_quantity = $list.children().length;
458					if (items_quantity > 0) {
459						$component.slideDown();
460					} else {
461						$component.slideUp();
462					}
463					if (data.isAtEnd) {
464						$actions.slideUp();
465					} else {
466						$actions.slideDown();
467					}
468				}
469			}, 'json');
470		},
471		LoadMore: function moreDictionaryNewWords() {
472			Dictionary.RecentWords.Refresh(false, false);
473		}
474	},
475
476	/** Fetch word data from the return data container by id
477		@return {object|undefined} */
478	GetWordById: function (_wordId) {
479		_wordId = parseInt(_wordId);
480		if (Dictionary.searchData.words !== undefined && Dictionary.searchData.words.length > 0) {
481			for (var i = 0; i < Dictionary.searchData.words.length; i++) {
482				if (Dictionary.searchData.words[i].Id === _wordId) {
483					return Dictionary.searchData.words[i];
484				}
485			}
486		}
487		return undefined;
488	},
489
490	/** Highlight text */
491	Highlight: function(selector, text, partial) {
492		text = typeof text !== 'undefined' ? text.replace(/[%*+]/g, '') 
492: '';
493		partial = partial || false;
494		if (text === '') return;
495		var list = [text];
496		if (!partial) {
497			list = $.trim(text).match(/(?:[^\s"]+|"[^"]*")+/g);
498		}
499		$.each(list, function (key, item) {
500			list[key] = item.replace(/[\\"]/g, '').replace(/-/g, '?');
501		});
502		$.each(list, function (key, item) {
503			$(selector).mark(item, {
504				'accuracy': partial
505					? 'partially'
506					: {
507						'value': 'exactly',
508						'limiters': [',', '.', ':', ';', '(', ')', '[', ']', '/']
509					},
510				'wildcards': 'withSpaces',
511				"synonyms": {
512					"и": "и́"
513				},
514				'ignoreJoiners': true,
515				'acrossElements': true,
516				'separateWordSearch': item.indexOf(' ') === -1
517			});
518		});
519	},
520
521	/** Highlight text (OLD) */
522	HighlightOLD: function(selector, text, partial) {
523		var arr = $.trim(text.replace(/[%*+"]/g, ' ')).split(' ');
524		for (var i = 0; i < arr.length; i++) {
525			if ($.trim(arr[i]) !== '') {
526				$(selector).highlight($.trim(arr[i])).highlight($.trim(arr[i]).replace('?', ''));
527			}
528		}
529	},
530
531	/** Highlight matched words */
532	HighlightMatchedWords: function(search_data) {
533		if (search_data.words.length > 0) {
534			if (Tools.getQueryVariable('_SearchDescriptions') === '0') {
535				Dictionary.Highlight('.dictionary-results--word-title', search_data.searchfor, true);
536			}
537			if (Tools.getQueryVariable('_SearchDescriptions') === '1') {
538				Dictionary.Highlight('.dictionary-results--word-description', search_data.searchfor, false);
539			}
540		}
541	},
542
543	/** Change the inflection of the dictionary owners name
544		@return {string} */
545	InitiateMasonry: function(search_data) {
546		if (search_data.dictionary.Type === 'cards') {
547			/*Macy({
548				container: '.dictionary-results--words',
549				columns: 3,
550				margin: { x: 48, y: 64 },
551				waitForImages: false,
552				breakAt: {
553					639: 1,
554					1023: 2
555				}
556			});*/
557		}
558	},
559
560	/** Change the inflection of the dictionary owners name
561		@return {string} */
562	InflectOwner: function(owner) {
563		if (owner.substring(owner.length - 4) === 'urin') {
564			return owner.substring(0, owner.length - 4) + 'in';
565		} else if (owner.substring(owner.length - 3) === 'tin') {
566			return owner.substring(0, owner.length - 3) + 'tan';
567		} else {
568			return owner;
569		}
570	},
571
572	/** Read text with readspeaker */
573	ReadText: function(text, language) {
574		var url = '';
575		if (language === 'gl') {
576			try {
577				var $tts_audio_player = $('#tts_audio_player');
578				$tts_audio_player[0].onended = function() {
579					var $dictionaryResults = $('.dictionary-results--component');
580					$dictionaryResults.find('.dictionary-results--word-icon--audio.dictionary-results--word-icon--active').removeClass('dictionary-results--word-icon--active');
581				};
582				$tts_audio_player.attr('src', 'http://gl.tts.sprotin.fo:8000/?t=' + text);
583				$tts_audio_player[0].play();
584			} catch (err) {
585				console.error(err)
586			}
587			return
588		}
589
590		var domain = 'https://app-eu.readspeaker.com/cgi-bin/rsent';
591		var customerId = 7214;
592		var lang = 'fo_fo';
593		var voice = 'hanus22k';
594		switch(language) {
595			case 'fo':
596				lang = 'fo_fo';
597				voice = 'hanus22k';
598				break;
599			case 'da':
600				lang = 'da_dk';
601				voice = 'mette22k';
602				break;
603			case 'de':
604				lang = 'de_de';
605				voice = 'de_hans';
606				break;
607			case 'en':
608				lang = 'en_uk';
609				voice = 'en_gb_brian';
610				break;
611			case 'es':
612				lang = 'es_es';
613				voice = 'Jorge';
614				break;
615			case 'ru':
616				lang = 'ru_ru';
617				voice = 'Milena';
618				break;
619			case 'fr':
620				lang = 'fr_fr';
621				voice = 'Benoit';
622				break;
623			case 'ki':
624				lang = 'zh_cn';
625				voice = 'Hui';
626				break;
627                        case 'jp':
628                                lang = 'jp_jp';
629                                voice = 'Akira';
630                                break;
631		}
632		$('#readspeaker1_word').text(text);
633		url = domain + '?customerid=' + customerId + '&lang=' + lang + '&readid=readspeaker1_word&voice=' + voice + '&url=' + encodeURIComponent('https://sprotin.fo/readspeaker.php');
634
635		//noinspection JSUnresolvedFunction
636		//readpage(url, 'readspeaker1');
637	},
638
639	/** Change dictionary page */
640	Page: function (_page, _max) {
641		switch (_page) {
642			case 'previous':
643				_page = parseInt(Tools.getQueryVariable('_DictionaryPage')) - 1;
644				_page = _page < 1 ? 1 : _page;
645				break;
646			case 'next':
647				_page = parseInt(Tools.getQueryVariable('_DictionaryPage')) + 1;
648				_page = ((typeof _max !== 'undefined') && (_page >
648 _max)) ? _max : _page;
649				break;
650		}
651		history.pushState(null, '', '?' + Tools.getQuery('_DictionaryPage,_WordId') + '&_DictionaryPage=' + _page);
652	},
653
654	/** Initiante a search of the dictionary */
655	Search: function(_SkipOtherDictionariesResults, _SkipSimilarWords, _SkipRefocus, _L) {
656
657		// Set initial variables and fetch/cache objects
658		_SkipOtherDictionariesResults = typeof _SkipOtherDictionariesResults === 'undefined' ? 0 : _SkipOtherDictionariesResults ? 1 : 0;
659		_SkipSimilarWords = typeof _SkipSimilarWords === 'undefined' ? 0 : _SkipSimilarWords ? 1 : 0;
660		_SkipRefocus = typeof _SkipRefocus === 'undefined' ? false : _SkipRefocus;
661		_L = typeof _L === 'undefined' ? false : _L;
662		var $dictionarySendSuggestion = $('.dictionary-send-suggestion--component');
663		var $dictionarySpellchecker = $('.dictionary-spellchecker--component');
664		var $dictionaryResults = $('.dictionary-results--component');
665		var $searchResults = $dictionaryResults.find('.dictionary-results--search-results');
666		var $no_words_found = $dictionaryResults.find('.dictionary-results--not-found');
667
668		// Refresh controls before doing search
669		Dictionary.RefreshControls();
670		var $dictionaryInput = $('.dictionary-input--component');
671		var $dictionaryInputTextbox = $dictionaryInput.find('.dictionary-input--textbox');
672		if (!_SkipRefocus) {
673			$dictionaryInputTextbox.select();
674		}
675
676		$searchResults.empty().addClass('dictionary-results--search-results--busy');
677		var params = {
678			'DictionaryId': Tools.getQueryVariable('_DictionaryId'),
679			'DictionaryPage': Tools.getQueryVariable('_DictionaryPage'),
680			'SearchFor': Tools.getQueryVariable('_SearchFor'),
681			'SearchInflections': Tools.getQueryVariable('_SearchInflections'),
682			'SearchDescriptions': Tools.getQueryVariable('_SearchDescriptions'),
683			'Group': Tools.getQueryVariable('_Group'),
684			'SkipOtherDictionariesResults': _SkipOtherDictionariesResults,
685			'SkipSimilarWords': _SkipSimilarWords,
686			'WordId': Tools.getQueryVariable('_WordId')
687		};
688		document.title = Tools.getQueryVariable('_SearchFor') + ' - Sprotin.fo'
689		if (_L) {
690			params['L'] = 1;
691		}
692		$.get('dictionary_search_json.php', params, function (return_data) {
693
694			// Remove current search results
695			$searchResults.empty();
696			// Save return data in the return data container
697			Dictionary.searchData = return_data;
698			return_data = null;
699			// Hide "no results found" message
700			$no_words_found.hide();
701			// Add type class to searchResults
702			$searchResults
703				.removeClass('dictionary-results--search-results--list')
704				.removeClass('dictionary-results--search-results--cards')
705				.addClass('dictionary-results--search-results--' + (Dictionary.searchData.dictionary ? Dictionary.searchData.dictionary.Type : ''));
706			// Prepare vars
707			var $dictionariesMainColumn = $('#dictionariesMainColumn');
708			var $dictionariesSideColumn = $('#dictionariesSideColumn');
709			var $group_selector_holder = null;
710
711
712			// Send suggestion
713			$dictionarySendSuggestion.find('.dictionary-send-suggestion--confirmation').hide();
714			$dictionarySendSuggestion.find('.dictionary-send-suggestion--self').show();
715			$dictionarySendSuggestion.find('.dictionary-send-suggestion--dictionary').text('\'' + Dictionary.searchData.dictionary.Title + '\'');
716			var $dictionarySendSuggestionInfo = $dictionarySendSuggestion.find('.dictionary-send-suggestion--info');
717			$dictionarySendSuggestionInfo.html($dictionarySendSuggestionInfo.attr('data-text').replace('{dictionary_title}', '<strong>' + Dictionary.searchData.dictionary.Title + '</strong>'));
718			var $dictionarySendSuggestionSubmit = $dictionarySendSuggestion.find('.dictionary-send-suggestion--submit');
719			$dictionarySendSuggestionSubmit.text($dictionarySendSuggestionSubmit.attr('data-text').replace('{dictionary_owner}', Dictionary.InflectOwner(Dictionary.searchData.dictionary.Owner)));
720			var $dictionarySendSuggestionDictionaryId = $dictionarySendSuggestion.find('.dictionary-send-suggestion--dictionary-id');
721			$dictionarySendSuggestionDictionaryId.val(Dictionary.searchData.dictionary.Id);
722
723
724			// IF LIST, SHOW RIGHT SIDE COLUMN
725			if (Dictionary.searchData.dictionary.Type === 'list') {
726				$('#main--component').removeClass('site--main--gray');
727				$dictionariesMainColumn.attr({ 's': 12, 'm': 8, 'l': 8 });
728				$dictionariesSideColumn.show();
729
730			// ELSE IF CARDS, HIDE RIGHT SIDE COLUMN (and generate groups selector)
731			} else if (Dictionary.searchData.dictionary.Type === 'cards') {
732				$('#main--component').addClass('site--main--gray');
733				$dictionariesMainColumn.attr({ 's': 12, 'm': 12, 'l': 12 });
734				$dictionariesSideColumn.hide();
735			}
736
737
738			// IF NO RESULTS FOUND, SHOW "NO RESULTS FOUND" MESSAGE
739			if (Dictionary.searchData.status === 'not_found') {
740				$no_words_found.show();
741
742
743
744			// IF NO SEARCH TEXT, SHOW DICTIONARY INFO
745			} else if (Dictionary.searchData.status === 'no_searchtext') {
746				var $info = $(document.createElement('div'))
747					.addClass('dictionary-results--info')
748					.html(Dictionary.searchData.dictionary.Info
749						.replace(/{searchWords}/g, Tools.numberFormat(Dictionary.searchData.dictionary.TotalWords, 0, ',', '.'))
750						.replace(/{totalSearches}/g, Tools.numberFormat(Dictionary.searchData.dictionary.TotalSearches, 0, ',', '.'))
751					);
752				$searchResults.append($info);
753
754				// Generate group selector
755				$group_selector_holder = Dictionary.GenerateGroupSelector(Dictionary.searchData);
756				if ($group_selector_holder) {
757					// Add group selector to results element
758					$searchResults.append($group_selector_holder);
759					// Make group selector into selectator
760					$group_selector_holder.find('.dictionary-results--group-selector').selectator({
761						useSearch: false
762					});
763				}
764
765
766
767			// IF SINGLE WORD IS CHOSEN
768			} else if (Dictionary.searchData.status === 'single_word') {
769
770				// Generate summary
771				var $dictionary_summary = Dictionary.GenerateSummary(
772					Dictionary.searchData,
773					$searchResults.attr('data-dictionary-summary'),
774					$searchResults.attr('data-cards-summary')
775				);
776				$searchResults.append($dictionary_summary);
777
778				// Generate pager
779				/*var $pager = Dictionary.GeneratePager(
780					Dictionary.searchData,
781					$searchResults.attr('data-pager-summary')
782				);
783				$searchResults.append($pager);*/
784
785				// Generate group selector
786				$group_selector_holder = Dictionary.GenerateGroupSelector(Dictionary.searchData);
787				if ($group_selector_holder) {
788					// Add group selector to results element
789					$searchResults.append($group_selector_holder);
790					// Make group selector into selectator
791					$group_selector_holder.find('.dictionary-results--group-selector').selectator({
792						useSearch: false
793					});
794				}
795
796				// Generate words holder
797				var $words = $(document.createElement('div'))
798					.addClass('dictionary-results--words dictionary-results--words--single-word');
799
800				// Generate single word
801				var $single_word_holder = $(document.createElement('div'))
802					.addClass('dictionary-results--single-word-holder')
803					.attr({ 's': 12, 'm': 8, 'l': 8 });
804				var $singleWord = Dictionary.GenerateSingleWord(Dictionary.searchData.single_word);
805				$single_word_holder.append($singleWord);
806
807				// Create words from same groups
808				if (typeof Dictionary.searchData.words_from_same_groups !== 'undefined') {
809					if (Dictionary.searchData.words_from_same_groups.length) {
810
811						// Create word from same groups title
812						var $wordsFromSameGroupsTitle = $(document.createElement('h4'))
813							.addClass('dictionary-results--words-from-same-groups-title')
814							.text(__('dictionaries', 'other_images'));
815						if (Dictionary.searchData.single_word.Groups && Dictionary.searchData.single_word.Groups.length) {
816							var isFirst = true;
817							$.each(Dictionary.searchData.single_word.Groups, function (i, group) {
818								if (!isFirst)
819									$wordsFromSameGroupsTitle.append('<span style="font-weight: 300;">,</span> ');
820								else
821									$wordsFromSameGroupsTitle.append(' ');
822								var $group = $(document.createElement('a'))
823									.addClass('dictionary-results--words-from-same-groups-title-group')
824									.attr('data-group-id', group.id)
825									.text(group.title);
826								$wordsFromSameGroupsTitle.append($group);
827								isFirst = false;
828							});
829						}
830						$single_word_holder.append($wordsFromSameGroupsTitle);
831
832						// Create word from same groups
833						var $words_from_same_groups = $(document.createElement('div'))
834							.addClass('dictionary-results--words-from-same-groups')
835							.attr({ 's': 12 });
836						for (var i = 0; i < Dictionary.searchData.words_from_same_groups.length; i++) {
837							// Generate word from same groups
838							var $word_from_same_groups = Dictionary.GenerateWord(Dictionary.searchData.words_from_same_groups[i]);
839							$word_from_same_groups.addClass('dictionary-results--word-outer--word-from-same-groups');
840							$word_from_same_groups.find('.dictionary-results--word').addClass('dictionary-results--word--word-from-same-groups');
841							// Append word-from-same-groups to words-from-same-groups element
842							$words_from_same_groups.append($word_from_same_groups);
843						}
844						$single_word_holder.append($words_from_same_groups);
845
846					}
847				}
848				$words.append($single_word_holder);
849
850				// Create related words
851				if (typeof Dictionary.searchData.related_words !== 'undefined') {
852					// Create related words holder
853					var $related_words = $(document.createElement('div'))
854						.addClass('dictionary-results--related-words')
855						.attr({ 's': 12, 'm': 4, 'l': 4 });
856					for (var i = 0; i < Dictionary.searchData.related_words.length; i++) {
857						// Generate related word
858						var $related_word = Dictionary.GenerateWord(Dictionary.searchData.related_words[i]);
859						$related_word.addClass('dictionary-results--word-outer--related-word');
860						$related_word.find('.dictionary-results--word').addClass('dictionary-results--word--related-word');
861						// Append related word to results element
862						$related_words.append($related_word);
863					}
864					$words.append($related_words);
865				}
866				$searchResults.append($words);
867
868				// Highlight matched word
869				if (typeof Dictionary.searchData.words !== 'undefined') {
870					Dictionary.HighlightMatchedWords(Dictionary.searchData);
871				}
872
873				// Initialize audioplayers
874				$singleWord.each(function () {
875					var $word = $(this);
876					$word.find('audio').each(function () {
877						$(this).audiotor({ truncateFilenameAfter: '_' });
878						//var $audio = $(this);
879						//var $button = document.createElement('button');
880						//$audio.after($button);
881						//AudioPlayer.init(this, null, $button);
882					});
883				});
884
885
886			// IF SEARCH TEXT IS VALID, AND RESULTS WERE FOUND
887			} else if (Dictionary.searchData.status === 'success') {
888
889				// Generate summary
890				var $dictionary_summary = Dictionary.GenerateSummary(
891					Dictionary.searchData,
892					$searchResults.attr('data-dictionary-summary'),
893					$searchResults.attr('data-cards-summary')
894				);
895				$searchResults.append($dictionary_summary);
896
897				// Generate pager
898				var $pager = Dictionary.GeneratePager(
899					Dictionary.searchData,
900					$searchResults.attr('data-pager-summary')
901				);
902				$searchResults.append($pager);
903
904				// Generate group selector
905				$group_selector_holder = Dictionary.GenerateGroupSelector(Dictionary.searchData);
906				if ($group_selector_holder) {
907					// Add group selector to results element
908					$searchResults.append($group_selector_holder);
909					// Make group selector into selectator
910					$group_selector_holder.find('.dictionary-results--group-selector').selectator({
911						useSearch: false
912					});
913				}
914
915				// Create dictionary search results
916				if (typeof Dictionary.searchData.words !== 'undefined') {
917
918					// Create words holder
919					var $words = $(document.createElement('div')).addClass('dictionary-results--words');
920					for (var i = 0; i < Dictionary.searchData.words.length; i++) {
921						// Generate word
922						var $word = Dictionary.GenerateWord(Dictionary.searchData.words[i]);
923						// Append word to results element
924						$words.append($word);
925					}
926					$searchResults.append($words);
927
928					// Highlight matched word
929					if (!Dictionary.searchData.search_inflections) {
930						Dictionary.HighlightMatchedWords(Dictionary.searchData);
931					}
932				}
933
934				// Initiate masonry if cards
935				Dictionary.InitiateMasonry(Dictionary.searchData);
936
937				// Clone pager for after search results
938				$searchResults.append($pager.clone().addClass('dictionary-results--pager--bottom'));
939			}
940
941			// Refresh other dictionaries search entries found
942			Dictionary.RefreshOtherDictionaries(Dictionary.searchData);
943
944			// Refresh word suggestions (left section suggestion when no result is found)
945			Dictionary.RefreshWordSuggestions(Dictionary.searchData);
946
947			// Refresh similar words
948			Dictionary.GenerateSimilarWords(Dictionary.searchData);
949
950			// Refresh most recent words
951			Dictionary.RecentWords.Refresh();
952
953			// Refresh popular words
954			Dictionary.GeneratePopularWords(Dictionary.searchData);
955
956			// Refresh dicitonary info
957			Dictionary.GenerateAboutDictionary(Dictionary.searchData);
958
959			// Refresh searches by country
960			Dictionary.GenerateSearchesByCountry(Dictionary.searchData);
961
962			// Remove busy class
963			$searchResults.removeClass('dictionary-results--search-results--busy');
964
965			// Check inflections for searchword and open if necessary
966			if (Dictionary.searchData.search_inflections) {
967				for (var i = 0; i < Dictionary.searchData.words.length; i++) {
968					var word = Dictionary.searchData.words[i];
969					Dictionary.Inflection.Toggle(word.Id);
970				}
971				/*
972				var searchfor = Dictionary.searchData.searchfor.toLowerCase();
973				for (var i = 0; i < Dictionary.searchData.words.length; i++) {
974					var word = Dictionary.searchData.words[i];
975					var searchword = word.SearchWord ? word.SearchWord.toLowerCase() : '';
976					var displayword = word.DisplayWord ? word.DisplayWord.toLowerCase() : '';
977					// skip if searchfor matches the base searchword (lemma)
978					if (searchfor === searchword || searchfor === displayword) {
979						continue;
980					}
981					// skip if no inflected form
982					if (!word.InflectedForm) {
983						continue;
984					}
985					// If searchfor is found in inflections, show inflections
986					var inflectedFormComputed = word.InflectedForm.map(function (inflection) {
987						return inflection.toLowerCase().split(new RegExp('[/-]', 'g'))
988					}).reduce(function(prev, curr) {
989						return prev.concat(curr)
990					});
991					if ($.inArray(searchfor, inflectedFormComputed) !== -1) {
992						Dictionary.Inflection.Toggle(word.Id);
993					}
994				}
995				*/
996			}
997
998
999		}, 'json');
1000	},
1001
1002	/** Generate word */
1003	GenerateWord: function (word_data) {
1004		/** Create word outer-container */
1005		var $wordOuter = $(document.createElement('div'))
1006			.addClass('dictionary-results--word-outer dictionary-results--word-outer--' + Dictionary.searchData.dictionary.Table)
1007			// .attr('id', 'word-id_' + word_data.Id)
1008			.attr('data-word-searchword', word_data.SearchWord)
1009			.attr('data-word-id', word_data.Id);
1010		if (Dictionary.searchData.dictionary.Type === 'cards') {
1011			$wordOuter.addClass('dictionary-results--word-outer--card')
1012		}
1013
1014		/** Create word container */
1015		var $word = $(document.createElement('div'))
1016			.addClass('dictionary-results--word dictionary-results--word--' + Dictionary.searchData.dictionary.Table)
1017			.attr('id', 'word-id_' + word_data.Id)
1018			.attr('data-word-searchword', word_data.SearchWord)
1019			.attr('data-word-id', word_data.Id);
1020		if (Dictionary.searchData.dictionary.Type === 'cards') {
1021			$word.addClass('dictionary-results--word--card')
1022		}
1023
1024		/** Create word image for cards */
1025		if (Dictionary.searchData.dictionary.Type === 'cards' && word_data.ImageFilename) {
1026			var $image = $(document.createElement('img'))
1027				.addClass('dictionary-results--word-image')
1028				.attr('src', word_data.ImageFilename);
1029			$word.append($image);
1030		}
1031
1032		/** Create word title */
1033		var $title = $(document.createElement('div'))
1034			.addClass('dictionary-results--word-title ')
1035			.html(' ' + word_data.SearchWord + (word_data.WordNr !== null ? '<sup>' + word_data.WordNr + '</sup>' : '') + ' ');
1036		$word.append($title);
1037		//if (Dictionary.searchData.dictionary.Type === 'cards') {
1038
1039		/** Create Subtitle section (text to the right of searchword/title) */
1040		if (Dictionary.searchData.dictionary.Type === 'list') {
1041			var $subtitle = $(document.createElement('div'))
1042				.addClass('dictionary-results--word-subtitle')
1043				.html($.trim(
1044					(word_data.Phonetic !== null ? '<span class="dictionary-results--word-phonetic">' + word_data.Phonetic + '</span> ' : '') + ' ' +
1045					(word_data.ShortInflectedForm !== null ? '<span class="dictionary-results--word-short-info">' + word_data.ShortInflectedForm + '</span>' : '') + ' ' +
1046					(word_data.InflexCats !== null ? '<span class="dictionary-results--word-short-info">' + word_data.InflexCats + '</span>' : '') + ' ' +
1047					(word_data.GrammarComment !== null ? ' <span class="dictionary-results--word-short-info">' + word_data.GrammarComment + '</span>' : '')
1048					)
1049				);
1050			$word.append($subtitle);
1051		}
1052
1053		/** Create actions */
1054		if (Dictionary.searchData.dictionary.Type === 'list') {
1055
1056			/** Create actions container */
1057			var $actions = $(document.createElement('div'))
1058				.addClass('dictionary-results--word-actions');
1059
1060			/** Create actions separator (used further down) */
1061			var $actions_separator = $(document.createElement('div'))
1062				.addClass('dictionary-results--word-actions-separator');
1063
1064			/** Create Inflections icon */
1065			if ((word_data.InflectedForm !== null && word_data.InflectedForm !== '') || Dictionary.searchData.dictionary.Table === 'fr-fo') {
1066				var $icon_inflectedform = $(document.createElement('a'))
1067					.addClass('dictionary-results--word-icon dictionary-results--word-icon--inflectedform')
1068					.attr('title', __('dictionaries', 'inflected_form'))
1069					.attr('data-word-id', word_data.Id)
1070					.attr('data-dictionary-table', Dictionary.searchData.dictionary.Table)
1071					.attr('data-searchword', word_data.SearchWord)
1072					.addClass('far fa-dot-circle')
1073					.text(__('dictionaries', 'inflected_form'));
1074				$actions.append($icon_inflectedform);
1075				$actions.append($actions_separator.clone());
1076			}
1077
1078			/** Create Audio icon (readspeaker) */
1079			var $icon_audio = $(document.createElement('a'))
1080				.addClass('dictionary-results--word-icon dictionary-results--word-icon--audio')
1081				.attr('title', __('dictionaries', 'audiofile'))
1082				.attr('data-text', word_data.SearchWord)
1083				.attr('data-language', Dictionary.searchData.dictionary.Table.substring(0, 2))
1084				.addClass('fas fa-volume-up')
1085				.text(__('dictionaries', 'audiofile'));
1086			$actions.append($icon_audio);
1087			$actions.append($actions_separator.clone());
1088
1089			/** Create Origin icon */
1090			if (word_data.Origin !== null && word_data.Origin !== '' && word_data.Origin.toLowerCase() !== '<br>') {
1091				var $icon_origin = $(document.createElement('a'))
1092					.addClass('dictionary-results--word-icon dictionary-results--word-icon--origin')
1093					.attr('title', __('dictionaries', 'word_origin'))
1094					.attr('data-word-id', word_data.Id)
1095					.addClass('fas fa-pencil-alt')
1096					.text(__('dictionaries', 'word_origin'));
1097				$actions.append($icon_origin);
1098				$actions.append($actions_separator.clone());
1099			}
1100
1101			/** Create Share icon */
1102			// var $icon_share = $(document.createElement('a'))
1103			// 	.addClass('dictionary-results--word-icon dictionary-results--word-icon--share')
1104			// 	.attr('title', __('dictionaries', 'share_word'))
1105			// 	.attr('data-word-id', word_data.Id)
1106			// 	.addClass('fas fa-share-square')
1107			// 	.text(__('dictionaries', 'share_word'));
1108			// $actions.append($icon_share);
1109			// $actions.append($actions_separator.clone());
1110
1111			/** Create Feedback icon */
1112			var $icon_feedback = $(document.createElement('a'))
1113				.addClass('dictionary-results--word-icon dictionary-results--word-icon--feedback')
1114				.attr('title', __('dictionaries', 'send_feedback'))
1115				.attr('data-word-id', word_data.Id)
1116				.addClass('fas fa-comment')
1117				.text(__('dictionaries', 'send_feedback'));
1118			$actions.append($icon_feedback);
1119
1120			/** Append actions to word */
1121			$word.append($actions);
1122		}
1123
1124		/*=====================================================================================*/
1125
1126		/** Create holder for actions data */
1127		if (Dictionary.searchData.dictionary.Type === 'list') {
1128			$word.append($(document.createElement('div')).addClass('dictionary-results--word-actions-data-holder'));
1129		}
1130
1131		/** Create Groups section */
1132		if (Dictionary.searchData.dictionary.Type === 'cards') {
1133			if (word_data.Groups && word_data.Groups.length) {
1134				var $groups = $(document.createElement('div'))
1135					.addClass('dictionary-results--word-groups');
1136				var isFirst = true;
1137				$.each(word_data.Groups, function (i, group) {
1138					if (!isFirst) {
1139						var $groupSeparator = $(document.createElement('span'))
1140							.addClass('dictionary-results--word-group-separator')
1141							.text(', ');
1142						$groups.append($groupSeparator);
1143					}
1144					var $group = $(document.createElement('a'))
1145						.addClass('dictionary-results--word-group')
1146						.attr('data-group-id', group.id)
1147						.text(group.title);
1148					$groups.append($group);
1149					isFirst = false;
1150				});
1151				$word.append($groups);
1152			}
1153		}
1154
1155		/** Create Description section (explanation) */
1156		var $description = $(document.createElement('div'));
1157		if (Dictionary.searchData.dictionary.Type === 'list') {
1158			// Prepare word links in text
1159			word_data.Explanation = word_data.Explanation.replace(/(<span class="word_link">)([^`]+?)(<\/span>)/gi, function (sAll, sStartTag, sWord, sEndTag) {
1160				if (Dictionary.searchData.dictionary.Table === 'ru-fo') {
1161					return '<a class="dictionary-results--word-link" data-searchfor="' + $.trim(sWord.replace(/\([^`]+?\)/g, '').replace(/[0-9]+/, '')) + '">' + sWord + '</a>'; //replace('(', '').replace(')', '')
1162				} else {
1163					//noinspection JSReferencingMutableVariableFromClosure
1164					return '<a class="dictionary-results--word-link" data-searchfor="' + $.trim(sWord.replace(/^-|-$/g, word_data.SearchWord.replace('-', '')).replace(/\([^`]+?\)/g, '').replace(/[0-9]+/, '')) + '">' + sWord + '</a>'; //replace('(', '').replace(')', '')
1165				}
1166			});
1167			$description
1168				.addClass('dictionary-results--word-description')
1169				.html(
1170					Tools.getQueryVariable('debug') !== undefined
1171						? word_data.Explanation + '<div class="dictionary-results--word-debug">' + Tools.htmlentities(word_data.Explanation, 'ENT_NOQUOTES').replace(/\n/gi, '<br>') + '</div>'
1172						: ' ' + word_data.Explanation + ' '
1173				);
1174
1175		} else if (Dictionary.searchData.dictionary.Type === 'cards') {
1176			var explanation = word_data.Explanation ? word_data.Explanation.replace(/(<([^>]+)>)/ig, '') : '';
1177			if (explanation.length > 120) {
1178				explanation = explanation.substr(0, 120) + '...';
1179			}
1180			$description
1181				.addClass('dictionary-results--word-description')
1182				.text(' ' + explanation + ' ');
1183		}
1184		$word.append($description);
1185
1186		$wordOuter.append($word);
1187
1188		return $wordOuter;
1189	},
1190
1191	/** Generate single word */
1192	GenerateSingleWord: function (word_data) {
1193
1194		/** Create single word container */
1195		var $word = $(document.createElement('div'))
1196			.addClass('dictionary-results--word dictionary-results--word--single-word dictionary-results--single-word--' + Dictionary.searchData.dictionary.Table)
1197			.attr('id', 'word-id_' + word_data.Id)
1198			.attr('data-word-searchword', word_data.SearchWord)
1199			.attr('data-word-id', word_data.Id);
1200		if (Dictionary.searchData.dictionary.Type === 'cards') {
1201			$word.addClass('dictionary-results--word--card')
1202		}
1203
1204		/** Create word image for cards */
1205		if (Dictionary.searchData.dictionary.Type === 'cards' && word_data.ImageFilename) {
1206			var $image = $(document.createElement('img'))
1207				.addClass('dictionary-results--word-image')
1208				.attr('src', word_data.ImageFilename);
1209			$word.append($image);
1210			if (word_data.ImageComment) {
1211				var $imageComment = $(document.createElement('div'))
1212					.addClass('dictionary-results--word-image-comment')
1213					.html(word_data.ImageComment);
1214				$word.append($imageComment);
1215			}
1216			if (word_data.ImageOwner) {
1217				var $imageOwner = $(document.createElement('div'))
1218					.addClass('dictionary-results--word-image-owner')
1219					.html('<i class="fas fa-camera"></i>&nbsp; ' + word_data.ImageOwner);
1220				$word.append($imageOwner);
1221			}
1222			$word.append($(document.createElement('div')).addClass('clearfix'));
1223		}
1224
1225		/** Create actions container */
1226		var $actions = $(document.createElement('div'))
1227			.addClass('dictionary-results--word-actions');
1228
1229		/** Create actions separator (used further down) */
1230		var $actions_separator = $(document.createElement('div'))
1231			.addClass('dictionary-results--word-actions-separator');
1232
1233		/** Create Inflections icon */
1234		if ((word_data.InflectedForm !== null && word_data.InflectedForm !== '') || Dictionary.searchData.dictionary.Table === 'fr-fo') {
1235			var $icon_inflectedform = $(document.createElement('a'))
1236				.addClass('dictionary-results--word-icon dictionary-results--word-icon--inflectedform')
1237				.attr('title', __('dictionaries', 'inflected_form'))
1238				.attr('data-word-id', word_data.Id)
1239				.attr('data-dictionary-table', Dictionary.searchData.dictionary.Table)
1240				.attr('data-searchword', word_data.SearchWord)
1241				.addClass('far fa-dot-circle')
1242				.text(__('dictionaries', 'inflected_form'));
1243			$actions.append($icon_inflectedform);
1244			$actions.append($actions_separator.clone());
1245		}
1246
1247		/** Create Audio icon (readspeaker) */
1248		var $icon_audio = $(document.createElement('a'))
1249			.addClass('dictionary-results--word-icon dictionary-results--word-icon--audio')
1250			.attr('title', __('dictionaries', 'audiofile'))
1251			.attr('data-text', word_data.SearchWord)
1252			.attr('data-language', Dictionary.searchData.dictionary.Table.substring(0, 2))
1253			.addClass('fas fa-volume-up')
1254			.text(__('dictionaries', 'audiofile'));
1255		$actions.append($icon_audio);
1256		$actions.append($actions_separator.clone());
1257
1258		/** Create Origin icon */
1259		if (word_data.Origin !== null && word_data.Origin !== '' && word_data.Origin.toLowerCase() !== '<br>') {
1260			var $icon_origin = $(document.createElement('a'))
1261				.addClass('dictionary-results--word-icon dictionary-results--word-icon--origin')
1262				.attr('title', __('dictionaries', 'word_origin'))
1263				.attr('data-word-id', word_data.Id)
1264				.addClass('fas fa-pencil-alt')
1265				.text(__('dictionaries', 'word_origin'));
1266			$actions.append($icon_origin);
1267			$actions.append($actions_separator.clone());
1268		}
1269
1270		/** Create Share icon */
1271		var $icon_share = $(document.createElement('a'))
1272			.addClass('dictionary-results--word-icon dictionary-results--word-icon--share')
1273			.attr('title', __('dictionaries', 'share_word'))
1274			.attr('data-word-id', word_data.Id)
1275			.addClass('fas fa-share-square')
1276			.text(__('dictionaries', 'share_word'));
1277		$actions.append($icon_share);
1278		$actions.append($actions_separator.clone());
1279
1280		/** Create Feedback icon */
1281		var $icon_feedback = $(document.createElement('a'))
1282			.addClass('dictionary-results--word-icon dictionary-results--word-icon--feedback')
1283			.attr('title', __('dictionaries', 'send_feedback'))
1284			.attr('data-word-id', word_data.Id)
1285			.addClass('fas fa-comment')
1286			.text(__('dictionaries', 'send_feedback'));
1287		$actions.append($icon_feedback);
1288
1289		/** Append actions to word */
1290		$word.append($actions);
1291
1292		/** Create word title */
1293		var $title = $(document.createElement('div'))
1294			.addClass('dictionary-results--word-title ')
1295			.html(' ' + word_data.SearchWord + (word_data.WordNr !== null ? '<sup>' + word_data.WordNr + '</sup>' : '') + ' ');
1296		$word.append($title);
1297
1298		/** Create Subtitle section (text to the right of searchword/title) */
1299		if (Dictionary.searchData.dictionary.Type === 'list') {
1300			var $subtitle = $(document.createElement('div'))
1301				.addClass('dictionary-results--word-subtitle')
1302				.html($.trim(
1303					(word_data.Phonetic !== null ? '<span class="dictionary-results--word-phonetic">' + word_data.Phonetic + '</span> ' : '') + ' ' +
1304					(word_data.ShortInflectedForm !== null ? '<span class="dictionary-results--word-short-info">' + word_data.ShortInflectedForm + '</span>' : '') + ' ' +
1305					(word_data.InflexCats !== null ? '<span class="dictionary-results--word-short-info">' + word_data.InflexCats + '</span>' : '') + ' ' +
1306					(word_data.GrammarComment !== null ? ' <span class="dictionary-results--word-short-info">' + word_data.GrammarComment + '</span>' : '')
1307					)
1308				);
1309			$word.append($subtitle);
1310		}
1311
1312		$word.append($(document.createElement('div')).addClass('dictionary-results--word-actions-data-holder'));
1313
1314		/** Create Groups section */
1315		if (Dictionary.searchData.dictionary.Type === 'cards') {
1316			if (word_data.Groups && word_data.Groups.length) {
1317				var $groups = $(document.createElement('div'))
1318					.addClass('dictionary-results--word-groups');
1319				var isFirst = true;
1320				$.each(word_data.Groups, function (i, group) {
1321					if (!isFirst) {
1322						var $groupSeparator = $(document.createElement('span'))
1323							.addClass('dictionary-results--word-group-separator')
1324							.text(', ');
1325						$groups.append($groupSeparator);
1326					}
1327					var $group = $(document.createElement('a'))
1328						.addClass('dictionary-results--word-group')
1329						.attr('data-group-id', group.id)
1330						.text(group.title);
1331					$groups.append($group);
1332					isFirst = false;
1333				});
1334				$word.append($groups);
1335			}
1336		}
1337
1338		/** Create Description section (explanation) */
1339		var $description = $(document.createElement('div'));
1340
1341		// Prepare word links in text
1342		word_data.Explanation = word_data.Explanation.replace(/(<span class="word_link">)([^`]+?)(<\/span>)/gi, function (sAll, sStartTag, sWord, sEndTag) {
1343			if (Dictionary.searchData.dictionary.Table === 'ru-fo') {
1344				return '<a class="dictionary-results--word-link" data-searchfor="' + $.trim(sWord.replace(/\([^`]+?\)/g, '').replace(/[0-9]+/, '')) + '">' + sWord + '</a>'; //replace('(', '').replace(')', '')
1345			} else {
1346				//noinspection JSReferencingMutableVariableFromClosure
1347				return '<a class="dictionary-results--word-link" data-searchfor="' + $.trim(sWord.replace(/^-|-$/g, word_data.SearchWord.replace('-', '')).replace(/\([^`]+?\)/g, '').replace(/[0-9]+/, '')) + '">' + sWord + '</a>'; //replace('(', '').replace(')', '')
1348			}
1349		});
1350		$description
1351			.addClass('dictionary-results--word-description')
1352			.html(
1353				Tools.getQueryVariable('debug') !== undefined
1354					? word_data.Explanation + '<div class="dictionary-results--word-debug">' + Tools.htmlentities(word_data.Explanation, 'ENT_NOQUOTES').replace(/\n/gi, '<br>') + '</div>'
1355					: word_data.Explanation
1356			);
1357
1358		$word.append($description);
1359
1360		return $word;
1361	},
1362
1363	/** Generate pager */
1364	GeneratePager: function(search_data, data_pager_summary) {
1365		// Create pager
1366		var $pager = $(document.createElement('div'))
1367			.addClass('dictionary-results--pager');
1368
1369		// Create results summary in pager
1370		if (search_data.total > 0) {
1371			var $pager_summary = $(document.createElement('div'))
1372				.addClass('dictionary-results--pager-summary')
1373				.html(
1374					data_pager_summary
1375						.replace('{from}', search_data.from)
1376						.replace('{to}', search_data.to)
1377						.replace('{total}', search_data.total)
1378						.replace('{time}', search_data.time)
1379				);
1380			$pager.append($pager_summary);
1381		}
1382
1383		// Create previous page arrow left in pager
1384		if (search_data.from !== 1) {
1385			var $arrow_left = $(document.createElement('a'))
1386				.addClass('dictionary-results--pager-item dictionary-results--pager-item--previous fal fa-angle-left');
1387			$pager.append($arrow_left);
1388		}
1389
1390		// Create next page arrow right in pager
1391		if (search_data.to < search_data.total) {
1392			var $arrow_right = $(document.createElement('a'))
1393				.addClass('dictionary-results--pager-item dictionary-results--pager-item--next fal fa-angle-right');
1394			$pager.append($arrow_right);
1395		}
1396
1397		return $pager;
1398	},
1399
1400	/** Generate summary */
1401	GenerateSummary: function (search_data, data_dictionary_summary, data_cards_summary) {
1402
1403		// Create dictionary summary
1404		var $dictionary_summary = $(document.createElement('div'))
1405			.addClass('dictionary-results--dictionary-summary')
1406			.html(
1407				data_dictionary_summary
1408					.replace('{dictionary}', '<a class="dictionary-results--show-info">' + search_data.dictionary.ShortTitle + '</a>')
1409					.replace('{dictionary_owner}', search_data.dictionary.Owner)
1410					.replace('{dictionary_owner_inflected}', search_data.dictionary.OwnerInflected)
1411					.replace('{dictionary_owner_url}', search_data.dictionary.OwnerUrl)
1412				+ '<br>'
1413			);
1414
1415		if (search_data.dictionary.Type === 'cards') {
1416			$dictionary_summary
1417				.append(data_cards_summary
1418					.replace(/{searchWords}/g, Tools.numberFormat(search_data.dictionary.TotalWords, 0, ',', '.'))
1419					.replace(/{totalSearches}/g, Tools.numberFormat(search_data.dictionary.TotalSearches, 0, ',', '.'))
1420				);
1421		}
1422
1423		$dictionary_summary.find('.dictionary-results--show-info').on('click', function () {
1424				history.pushState(null, '', '?' + Tools.getQuery('_SearchFor,_WordId,_Group') + '&_SearchFor=');
1425				Dictionary.Search(0, 0, false, false);
1426			}
1427		);
1428
1429		return $dictionary_summary;
1430	},
1431
1432	/** Generate group selector */
1433	GenerateGroupSelector: function (search_data) {
1434		if (search_data.dictionary.Type !== 'cards') {
1435			return null;
1436		}
1437
1438		// Create group selector holder
1439		var $group_selector_holder = $(document.createElement('div'))
1440			.addClass('dictionary-results--group-selector-holder selectator--component');
1441
1442		// Create group selector
1443		var $group_selector = $(document.createElement('select'))
1444			.addClass('dictionary-results--group-selector')
1445			.append($('<option>', {
1446				value: '',
1447				text: __('dictionaries', 'choose_group'),
1448				selected: !Tools.getQueryVariable('_Group')
1449			}));
1450		$.each(search_data.groups, function (i, group) {
1451			$group_selector
1452				.append($('<option>', {
1453					value: group.id,
1454					text: group.title,
1455					selected: parseInt(Tools.getQueryVariable('_Group')) === group.id,
1456					'data-right': group.words
1457				}));
1458		});
1459		$group_selector.on('change', function () {
1460			history.pushState(null, '', '?' + Tools.getQuery('_DictionaryPage,_Group,_WordId,_SearchFor,_SearchDescriptions') + '&_DictionaryPage=1&_SearchFor=&_SearchDescriptions=0&_Group=' + $group_selector.val());
1461			setTimeout(function() {
1462				Dictionary.Search(0, 0, false, true);
1463			}, 1);
1464		});
1465		$group_selector_holder.append($group_selector);
1466
1467		return $group_selector_holder;
1468	},
1469
1470	/** Refresh other dictionaries */
1471	RefreshOtherDictionaries: function (search_data) {
1472		var $dictionarySelectors = $('.dictionary-selector--component');
1473		for (var i = 0; i < search_data.dictionaries_results.length; i++) {
1474			var dictionaryId = search_data.dictionaries_results[i].id;
1475			var dictionaryResults = search_data.dictionaries_results[i].results;
1476			$dictionarySelectors
1477				.find('.dictionary-selector--item[data-id=' + dictionaryId + ']')
1478				.find('.dictionary-selector--total-results')
1479				.text(dictionaryResults);
1480		}
1481	},
1482
1483	/** Generate word suggestions */
1484	RefreshWordSuggestions: function (search_data) {
1485		var $notFoundSuggestions = $('.dictionary-results--not-found-suggestions');
1486		var $suggestionsItems = $notFoundSuggestions.find('.dictionary-results--not-found-suggestions-items');
1487		$suggestionsItems.empty();
1488		if (search_data.searchfor === '' || search_data.similar_words.length === 0) {
1489			$notFoundSuggestions.hide();
1490		} else {
1491			for (var i = 0; i < search_data.similar_words.length; i++) {
1492				var $suggestion = $(document.createElement('a'))
1493					.addClass('dictionary-results--not-found-suggestions-item')
1494					.attr('data-searchword', search_data.similar_words[i].SearchWord)
1495					.text(search_data.similar_words[i].SearchWord);
1496				$suggestionsItems.append($suggestion);
1497				if (i < search_data.similar_words.length-1) {
1498					$suggestionsItems.append(', ');
1499				}
1500			}
1501			$notFoundSuggestions.show();
1502		}
1503	},
1504
1505	/** Generate dictionary info */
1506	GenerateAboutDictionary: function (search_data) {
1507		var $dictionaryAboutDictionary = $('.dictionary-about-dictionary--component');
1508		var $dictionaryAboutDictionaryContent = $dictionaryAboutDictionary.find('.dictionary-about-dictionary--content');
1509		$dictionaryAboutDictionaryContent.html(
1510			search_data.dictionary.Info
1511				.replace(/{searchWords}/g,  Tools.numberFormat(search_data.dictionary.TotalWords, 0, ',', '.'))
1512				.replace(/{totalSearches}/g,  Tools.numberFormat(search_data.dictionary.TotalSearches, 0, ',', '.'))
1513		);
1514	},
1515
1516	/** Generate similar words */
1517	GenerateSimilarWords: function (search_data) {
1518		var $section_similar_words = $('#section_similar_words');
1519		var $section_similar_words_list = $section_similar_words.find('.list');
1520		$section_similar_words_list.empty();
1521		if (search_data.searchfor === '' || search_data.similar_words.length === 0) {
1522			$section_similar_words.slideUp();
1523		} else {
1524			$section_similar_words.children('.title').children('.searchword').html(search_data.searchfor);
1525			for (var i = 0; i < search_data.similar_words.length; i++) {
1526				var $similar_word_holder = $(document.createElement('li'))
1527					.addClass('item');
1528				var $similar_word = $(document.createElement('a'))
1529					.attr('data-searchword', search_data.similar_words[i].SearchWord)
1530					.text(search_data.similar_words[i].SearchWord);
1531				$similar_word_holder.append($similar_word);
1532				$section_similar_words_list.append($similar_word_holder);
1533			}
1534			$section_similar_words.slideDown();
1535		}
1536	},
1537
1538	/** Generate popular words */
1539	GeneratePopularWords: function (search_data) {
1540		var $dictionaryPopularWordsList = $('.dictionary-popular-words--list');
1541		$dictionaryPopularWordsList.empty();
1542		for (var i = 0; i < search_data.popular_words.length; i++) {
1543			var popular_word = search_data.popular_words[i];
1544			var $popular_word_holder = $(document.createElement('li'))
1545				.addClass('dictionary-popular-words--item');
1546			var $popular_word = $(document.createElement('a'))
1547				.addClass('dictionary-popular-words--link')
1548				.attr('data-searchfor', popular_word.SearchWord)
1549				.html(popular_word.SearchWord);
1550			$popular_word_holder.append($popular_word);
1551			$dictionaryPopularWordsList.append($popular_word_holder);
1552		}
1553
1554	},
1555
1556	/** Generate searches by country */
1557	GenerateSearchesByCountry: function (search_data) {
1558		var $dictionarySearchesByCountry = $('.dictionary-searches-by-country--component');
1559		var $dictionarySearchesByCountryList = $dictionarySearchesByCountry.find('.dictionary-searches-by-country--list');
1560		$dictionarySearchesByCountryList.empty();
1561		for (var i = 0; i < search_data.searches_by_country.length; i++) {
1562			var country_searches = search_data.searches_by_country[i];
1563			var $dictionarySearchesByCountryItem = $(document.createElement('li'))
1564				.addClass('dictionary-searches-by-country--item');
1565			var $dictionarySearchesByCountryPercent = $(document.createElement('div'))
1566				.addClass('dictionary-searches-by-country--percent')
1567				//.attr('title', country_searches.Quantity)
1568				.html(country_searches.Percent.toString().replace('.', ',') + '%');
1569			var $dictionarySearchesByCountryCountry = $(document.createElement('div'))
1570				.addClass('dictionary-searches-by-country--country')
1571				//.attr('title', country_searches.Country.replace('"', '\\"'))
1572				.html(country_searches.Country);
1573			$dictionarySearchesByCountryItem.append($dictionarySearchesByCountryPercent);
1574			$dictionarySearchesByCountryItem.append($dictionarySearchesByCountryCountry);
1575			$dictionarySearchesByCountryList.append($dictionarySearchesByCountryItem);
1576		}
1577	},
1578
1579	Inflection: {
1580		Toggle: function (_wordId) {
1581			var $dictionaryResults = $('.dictionary-results--component');
1582			var $searchResults = $dictionaryResults.find('.dictionary-results--search-results');
1583			var $word = $searchResults.find('.dictionary-results--word[data-word-id=' + _wordId + ']');
1584			var $word_actions_data_holder = $word.find('.dictionary-results--word-actions-data-holder');
1585
1586			// Inflected form holder
1587			if ($word_actions_data_holder.children('.dictionary-inflectedform--component').length === 0) {
1588				$word.find('.dictionary-results--word-icon--inflectedform').addClass('dictionary-results--word-icon--active');
1589				var word_data = Dictionary.GetWordById(_wordId);
1590				var $table, $tr, $th, $td, i, i2, i3, types1Array, types2Array, types3Array;
1591
1592				/** Tablet+ version */
1593				// container
1594				var $container = $(document.createElement('div'))
1595					.addClass('dictionary-inflectedform--component')
1596					.addClass('dictionary-inflectedform--component--tablet')
1597					.attr('so-visibility', 'hide')
1598					.hide();
1599				// dictionary owner
1600				var $owner = $(document.createElement('div'))
1601					.addClass('dictionary-inflectedform--editor')
1602					.html('&copy; Orðabókagrunnurin');
1603				// title
1604				var $title = $(document.createElement('div'))
1605					.addClass('dictionary-inflectedform--title')
1606					.html(__('dictionaries', 'inflected_form') + ' <span class="dictionary-inflectedform--searchWord">\'' + word_data.SearchWord + '\'</span>');
1607				// audio icon (readspeaker)
1608				var $audioicon = $(document.createElement('a'))
1609					.addClass('dictionary-inflectedform--audio fas fa-volume-up')
1610					.attr({
1611						'data-Text': word_data.InflectedForm.join(', '),
1612						'data-Language': Dictionary.searchData.dictionary.Table.substring(0, 2),
1613						'title': word_data.SearchWord
1614					}).on('click', function (e) {
1615						//e.preventDefault();
1616						//e.stopPropagation();
1617						//var $this = $(this);
1618						//Dictionary.ReadText($this.attr('data-Text'), $this.attr('data-Language'));
1619					});
1620				$title.append($audioicon);
1621				$container.append($owner);
1622				$container.append($title);
1623				//$audioicon.append($(document.createElement('div')).addClass('fas fa-volume-up'));
1624
1625				$table = $(document.createElement('table'));
1626				switch (word_data.InflectedForm.length) {
1627					case 6:
1628						for (var i = 0; i < 6; i++) {
1629							$tr = $(document.createElement('tr'));
1630							$th = $(document.createElement('th'))
1631								.css('width', '250px');
1632							switch(i) {
1633								case 0:
1634									$th.text('Navnháttur');
1635									break;
1636								case 1:
1637									$th.text('3. persónur eintal í nútíð');
1638									break;
1639								case 2:
1640									$th.text('eintal í tátíð');
1641									break;
1642								case 3:
1643									$th.text('fleirtal í tátíð');
1644									break;
1645								case 4:
1646									$th.text('lýsingarháttur í tátíð');
1647									break;
1648								case 5:
1649									$th.text('lýsingarháttur í tátíð, kallkyn hvørfall');
1650									break;
1651							}
1652							$tr.append($th);
1653							$td = $(document.createElement('td'))
1654								.addClass('dictionary-inflectedform--word')
1655								.html(' ' + word_data.InflectedForm[i].replace('/', '/<wbr>') + ' ');
1656							$tr.append($td);
1657							$table.append($tr);
1658						}
1659						$container.append($table);
1660						break;
1661					case 16:
1662						$tr = $(document.createElement('tr'));
1663						$td = $(document.createElement('td'));
1664						$tr.append($td);
1665						$td = $(document.createElement('td'));
1666						$tr.append($td);
1667						$th = $(document.createElement('th'))
1668							.text('óbundið / indef.');
1669						$tr.append($th);
1670						$th = $(document.createElement('th'))
1671							.text('bundið / def.');
1672						$tr.append($th);
1673						$table.append($tr);
1674						for (var i = 0; i < 8; i++) {
1675							$tr = $(document.createElement('tr'));
1676							// Column 1
1677							$th = $(document.createElement('th'))
1678								.css('width', '105px');
1679							switch(i) {
1680								case 0:
1681									$th.text('eintal / sing.');
1682									break;
1683								case 4:
1684									$th.text('fleirtal / plur.');
1685									break;
1686							}
1687							$tr.append($th);
1688							// Column 2
1689							$th = $(document.createElement('th'))
1690								.css('width', '150px');
1691							switch(i) {
1692								case 0:
1693								case 4:
1694									$th.text('hvørfall / nominativ');
1695									break;
1696								case 1:
1697								case 5:
1698									$th.text('hvønnfall / akkusativ');
1699									break;
1700								case 2:
1701								case 6:
1702									$th.text('hvørjumfall / dativ');
1703									break;
1704								case 3:
1705								case 7:
1706									$th.text('hvørsfall / genitiv');
1707									break;
1708							}
1709							$tr.append($th);
1710							// Column 3
1711							$td = $(document.createElement('td'))
1712								.css('width', '200px')
1713								.addClass('dictionary-inflectedform--word')
1714								.html(' ' + word_data.InflectedForm[i].replace('/', '/<wbr>'));
1715							$tr.append($td);
1716							// Column 4
1717							$td = $(document.createElement('td'))
1718								.css('width', '200px')
1719								.addClass('dictionary-inflectedform--word')
1720								.html(' ' + word_data.InflectedForm[i + 8].replace('/', '/<wbr>'));
1721							$tr.append($td);
1722							$table.append($tr);
1723						}
1724						$container.append($table);
1725						break;
1726					case 24:
1727						$tr = $(document.createElement('tr'));
1728						$td = $(document.createElement('td'));
1729						$tr.append($td);
1730						$td = $(document.createElement('td'));
1731						$tr.append($td);
1732						$th = $(document.createElement('th'))
1733							.text('kallkyn / mask.');
1734						$tr.append($th);
1735						$th = $(document.createElement('th'))
1736							.text('kvennkyn / fem.');
1737						$tr.append($th);
1738						$th = $(document.createElement('th'))
1739							.text('hvørkikyn / neutr.');
1740						$tr.append($th);
1741						$table.append($tr);
1742						for (var i = 0; i < 8; i++) {
1743							$tr = $(document.createElement('tr'));
1744							// Column 1
1745							$th = $(document.createElement('th'))
1746								.css('width', '105px');
1747							switch(i) {
1748								case 0:
1749									$th.text('eintal / sing.');
1750									break;
1751								case 4:
1752									$th.text('fleirtal / plur.');
1753									break;
1754							}
1755							$tr.append($th);
1756							// Column 2
1757							$th = $(document.createElement('th'))
1758								.css('width', '150px');
1759							switch(i) {
1760								case 0:
1761								case 4:
1762									$th.text('hvørfall / nominativ');
1763									break;
1764								case 1:
1765								case 5:
1766									$th.text('hvønnfall / akkusativ');
1767									break;
1768								case 2:
1769								case 6:
1770									$th.text('hvørjumfall / dativ');
1771									break;
1772								case 3:
1773								case 7:
1774									$th.text('hvørsfall / genitiv');
1775									break;
1776							}
1777							$tr.append($th);
1778							// Column 3
1779							$td = $(document.createElement('td'))
1780								.css('width', '135px')
1781								.addClass('dictionary-inflectedform--word')
1782								.html(' ' + word_data.InflectedForm[i].replace('/', '/<wbr>'));
1783							$tr.append($td);
1784							// Column 4
1785							$td = $(document.createElement('td'))
1786								.css('width', '135px')
1787								.addClass('dictionary-inflectedform--word')
1788								.html(' ' + word_data.InflectedForm[i + 8].replace('/', '/<wbr>'));
1789							$tr.append($td);
1790							// Column 5
1791							$td = $(document.createElement('td'))
1792								.css('width', '135px')
1793								.addClass('dictionary-inflectedform--word')
1794								.html(' ' + word_data.InflectedForm[i + 16].replace('/', '/<wbr>'));
1795							$tr.append($td);
1796							$table.append($tr);
1797						}
1798						$container.append($table);
1799						break;
1800				}
1801				$word_actions_data_holder.append($container);
1802
1803				/** Phone version */
1804				// container 2
1805				var $container2 = $(document.createElement('div'))
1806					.addClass('dictionary-inflectedform--component')
1807					.addClass('dictionary-inflectedform--component--phone')
1808					.attr('m-visibility', 'hide')
1809					.hide();
1810				// title 2
1811				var $title2 = $(document.createElement('div'))
1812					.addClass('dictionary-inflectedform--title')
1813					.html(__('dictionaries', 'inflected_form') + ' <span class="dictionary-inflectedform--searchWord">\'' + word_data.SearchWord + '\'</span>');
1814				$container2.append($title2);
1815				// audio icon (readspeaker)
1816				$title2.append($audioicon.clone(true, true));
1817
1818				$table = $(document.createElement('table'));
1819				switch (word_data.InflectedForm.length) {
1820					case 6:
1821						var typesArray = [
1822							'Navnháttur',
1823							'3. persónur<br> eintal í nútíð',
1824							'eintal í tátíð',
1825							'fleirtal í tátíð',
1826							'lýsingarháttur í tátíð',
1827							'lýsingarháttur í tátíð,<br> kallkyn hvørfall'
1828						];
1829						for (var i = 0; i < 6; i++) {
1830							$tr = $(document.createElement('tr'));
1831							if (i === 0) {
1832								$tr.addClass('dictionary-inflectedform--firstrow');
1833							}
1834							$th = $(document.createElement('th'))
1835								.addClass('dictionary-inflectedform--row')
1836								.html(typesArray[i]);
1837							$tr.append($th);
1838							$td = $(document.createElement('td'))
1839								.addClass('dictionary-inflectedform--row')
1840								.addClass('dictionary-inflectedform--word')
1841								.text(' ' + word_data.InflectedForm[i]);
1842							$tr.append($td);
1843							$table.append($tr);
1844						}
1845						break;
1846					case 16:
1847						types1Array = [
1848							'óbundið / indef.',
1849							'bundið / def.'
1850						];
1851						types2Array = [
1852							'eintal / sing.',
1853							'fleirtal / plur.'
1854						];
1855						types3Array = [
1856							'hvørfall /<br>nominativ',
1857							'hvønnfall /<br>akkusativ',
1858							'hvørjumfall /<br>dativ',
1859							'hvørsfall /<br>genetiv'
1860						];
1861						for (var i = 0; i < 2; i++) {
1862							for (var i2 = 0; i2 < 2; i2++) {
1863								$tr = $(document.createElement('tr'));
1864								$th = $(document.createElement('th'))
1865									.attr('colspan', 2)
1866									.addClass('dictionary-inflectedform--header-cell')
1867									.html(types1Array[i] + '<br>' + types2Array[i2]);
1868								$tr.append($th);
1869								$table.append($tr);
1870								for (var i3 = 0; i3 < 4; i3++) {
1871									$tr = $(document.createElement('tr'));
1872									if (i3 === 0) {
1873										$tr.addClass('dictionary-inflectedform--firstrow');
1874									}
1875									$th = $(document.createElement('th'))
1876										.addClass('dictionary-inflectedform--row')
1877										.html(types3Array[i3]);
1878									$tr.append($th);
1879									$td = $(document.createElement('td'))
1880										.addClass('dictionary-inflectedform--row')
1881										.addClass('dictionary-inflectedform--word')
1882										.text(' ' + word_data.InflectedForm[(i * 8) + (i2 * 4) + i3]);
1883									$tr.append($td);
1884									$table.append($tr);
1885								}
1886							}
1887						}
1888						break;
1889					case 24:
1890						types2Array = [
1891							'kallkyn / mask.',
1892							'kvennkyn / fem.',
1893							'hvørkikyn / neutr.'
1894						];
1895						types1Array = [
1896							'óbundið / indef.',
1897							'bundið / def.'
1898						];
1899						types3Array = [
1900							'hvørfall /<br>nominativ',
1901							'hvønnfall /<br>akkusativ',
1902							'hvørjumfall /<br>dativ',
1903							'hvørsfall /<br>genetiv'
1904						];
1905						for (var i2 = 0; i2 < 3; i2++) {
1906							for (var i = 0; i < 2; i++) {
1907								$tr = $(document.createElement('tr'));
1908								$th = $(document.createElement('th'))
1909									.attr('colspan', 2)
1910									.addClass('dictionary-inflectedform--header-cell')
1911									.html(types1Array[i] + '<br>' + types2Array[i2]);
1912								$tr.append($th);
1913								$table.append($tr);
1914								for (var i3 = 0; i3 < 4; i3++) {
1915									$tr = $(document.createElement('tr'));
1916									if (i3 === 0) {
1917										$tr.addClass('dictionary-inflectedform--firstrow');
1918									}
1919									$th = $(document.createElement('th'))
1920										.addClass('dictionary-inflectedform--row')
1921										.html(types3Array[i3]);
1922									$tr.append($th);
1923									$td = $(document.createElement('td'))
1924										.addClass('dictionary-inflectedform--row')
1925										.addClass('dictionary-inflectedform--word')
1926										.text(' ' + word_data.InflectedForm[(i2 * 8) + (i * 4) + i3]);
1927									$tr.append($td);
1928									$table.append($tr);
1929								}
1930							}
1931						}
1932						break;
1933				}
1934				$container2.append($table);
1935				$word_actions_data_holder.append($container2);
1936
1937				Dictionary.Highlight('.dictionary-inflectedform--word', $('.dictionary-input--textbox').val().replace(/\\"/g, ''), false);
1938
1939				$word_actions_data_holder.find('.dictionary-inflectedform--component').slideDown();
1940
1941			} else {
1942				$word.find('.dictionary-results--word-icon--inflectedform').removeClass('dictionary-results--word-icon--active');
1943				$word_actions_data_holder.find('.dictionary-inflectedform--component').slideUp(function () {
1944					$(this).remove();
1945				});
1946			}
1947		}
1948	},
1949
1950	Images: {
1951		Toggle: function (_wordId) {
1952		}
1953	},
1954
1955	Video: {
1956		Toggle: function (_wordId) {
1957		}
1958	},
1959
1960	Wikipedia: {
1961		Toggle: function (_wordId) {
1962		}
1963	},
1964
1965	Origin: {
1966		Toggle: function (_wordId) {
1967			var $dictionaryResults = $('.dictionary-results--component');
1968			var $searchResults = $dictionaryResults.find('.dictionary-results--search-results');
1969			var $word = $searchResults.find('.dictionary-results--word[data-word-id=' + _wordId + ']');
1970			var $word_actions_data_holder = $word.find('.dictionary-results--word-actions-data-holder');
1971
1972			// Origin holder
1973			if ($word_actions_data_holder.children('.dictionary-origin--component').length === 0) {
1974				$word.find('.dictionary-results--word-icon--origin').addClass('dictionary-results--word-icon--active');
1975				var word_data = Dictionary.GetWordById(_wordId);
1976
1977				// container
1978				var $container = $(document.createElement('div'))
1979					.addClass('dictionary-origin--component')
1980					.hide();
1981				// title
1982				var $title = $(document.createElement('div'))
1983					.addClass('dictionary-origin--title')
1984					.html(__('dictionaries', 'word_origin') + ' <span class="dictionary-share--searchWord">\'' + word_data.SearchWord + '\'</span>');
1985				// content
1986				var $content = $(document.createElement('div'))
1987					.addClass('dictionary-origin--content')
1988					.html(word_data.Origin);
1989				// append elements
1990				$container.append($title);
1991				$container.append($content);
1992				$word_actions_data_holder.append($container);
1993				$word_actions_data_holder.find('.dictionary-origin--component').slideDown();
1994			} else {
1995				$word.find('.dictionary-results--word-icon--origin').removeClass('dictionary-results--word-icon--active');
1996				$word_actions_data_holder.find('.dictionary-origin--component').slideUp(function () {
1997					$(this).remove();
1998				});
1999			}
2000		}
2001	},
2002
2003	Share: {
2004		Toggle: function (_wordId) {
2005
2006			var $dictionaryResults = $('.dictionary-results--component');
2007			var $searchResults = $dictionaryResults.find('.dictionary-results--search-results');
2008			var $word = $searchResults.find('.dictionary-results--word[data-word-id=' + _wordId + ']');
2009			var $word_actions_data_holder = $word.find('.dictionary-results--word-actions-data-holder');
2010
2011			// Share holder
2012			if ($word_actions_data_holder.children('.dictionary-share--component').length === 0) {
2013				$word.find('.dictionary-results--word-icon--share').addClass('dictionary-results--word-icon--active');
2014				var word_data = Dictionary.GetWordById(_wordId);
2015
2016				// container
2017				var $container = $(document.createElement('div'))
2018					.addClass('dictionary-share--component')
2019					.hide();
2020				// title
2021				var $title = $(document.createElement('div'))
2022					.addClass('dictionary-share--title')
2023					.html(__('dictionaries', 'share') + ' <span class="dictionary-share--searchWord">\'' + word_data.SearchWord + '\'</span>');
2024				// content
2025				var $content = $(document.createElement('div'))
2026					.addClass('dictionary-share--content');
2027				// addthis_toolbox
2028				// var $addthis_toolbox =  $(document.createElement('div'))
2029				// 	.addClass('dictionary-share--addthis-toolbox')
2030				// 	.attr('id', 'addthis_toolbox_word-id_' + word_data.Id)
2031				// 	.attr('addthis:title', word_data.SearchWord)
2032				// 	.attr('addthis:description', word_data.Explanation.replace(/(<([^>]+)>)/ig, '').replace(/"/ig, '&quot;').replace(/\n/ig, ' '))
2033				// 	.attr('addthis:url', window.location.hostname + '/dictionaries?' + Tools.getQuery('_SearchFor,_DictionaryPage,_SearchInflections,_SearchDescriptions,_Group,_l') + '&_DictionaryPage=1&_SearchInflections=0&_SearchDescriptions=0&_Group=&_WordId=' + word_data.Id + '&_SearchFor=' + word_data.SearchWord + '&_l=fo');
2034				// // custom_images
2035				var $custom_images =  $(document.createElement('div'))
2036					.addClass('dictionary-share--custom-images');
2037				// facebook
2038				var $facebook =  $(document.createElement('a'))
2039					.addClass('addthis_button_facebook')
2040					.append($(document.createElement('div'))
2041						.addClass('dictionary-share--facebook fab fa-facebook')
2042						.attr('title', __('dictionaries', 'share_to_facebook'))
2043					);
2044				// twitter
2045				var $twitter =  $(document.createElement('a'))
2046					.addClass('addthis_button_twitter')
2047					.append($(document.createElement('div'))
2048						.addClass('dictionary-share--twitter fab fa-twitter')
2049						.attr('title', __('dictionaries', 'share_to_twitter'))
2050					);
2051				// pinterest
2052				var $pinterest_holder =  $(document.createElement('div'))
2053					.addClass('dictionary-share--pinterest-holder')
2054					.append($(document.createElement('a'))
2055						.addClass('addthis_button_pinterest')
2056					)
2057					.append($(document.createElement('div'))
2058						.addClass('dictionary-share--pinterest fab fa-pinterest')
2059						.attr('title', __('dictionaries', 'share_to_pinterest'))
2060					);
2061				// email
2062				var $email =  $(document.createElement('a'))
2063					.addClass('addthis_button_email')
2064					.append($(document.createElement('div'))
2065						.addClass('dictionary-share--envelope fas fa-envelope')
2066						.attr('title', __('dictionaries', 'share_to_email'))
2067					);
2068				// append elements
2069				$custom_images
2070					.append($facebook)
2071					.append($twitter)
2072					.append($pinterest_holder)
2073					.append($email);
2074				$addthis_toolbox.append($custom_images);
2075				$container.append($title);
2076				$container.append($addthis_toolbox);
2077				$word_actions_data_holder.append($container);
2078				$word_actions_data_holder.find('.dictionary-share--component').slideDown(function () {
2079					if (typeof addthis === 'object') {
2080						//noinspection JSUnresolvedFunction
2081						addthis.toolbox('#addthis_toolbox_word-id_' + word_data.Id);
2082					}
2083					if (typeof addthis !== 'undefined') {
2084						if (typeof addthis === 'object' && typeof addthis.layers.refresh !== 'undefined') {
2085							addthis.layers.refresh();
2086						} else {
2087							setTimeout(function () {
2088								if (typeof addthis === 'object' && typeof addthis.layers.refresh !== 'undefined') {
2089									addthis.layers.refresh();
2090								}
2091							}, 1000)
2092						}
2093					}
2094
2095				});
2096			} else {
2097				$word.find('.dictionary-results--word-icon--share').removeClass('dictionary-results--word-icon--active');
2098				$word_actions_data_holder.find('.dictionary-share--component').slideUp(function () {
2099					$(this).remove();
2100				});
2101			}
2102		}
2103	},
2104
2105	Feedback: {
2106		Toggle: function (_wordId) {
2107			var $dictionaryResults = $('.dictionary-results--component');
2108			var $searchResults = $dictionaryResults.find('.dictionary-results--search-results');
2109			var $word = $searchResults.find('.dictionary-results--word[data-word-id=' + _wordId + ']');
2110			var $word_actions_data_holder = $word.find('.dictionary-results--word-actions-data-holder');
2111
2112			// Feedback holder
2113			if ($word_actions_data_holder.children('.dictionary-feedback--component').length === 0) {
2114				$word.find('.dictionary-results--word-icon--feedback').addClass('dictionary-results--word-icon--active');
2115				var word_data = Dictionary.GetWordById(_wordId);
2116
2117				// container
2118				var $container = $(document.createElement('div'))
2119					.addClass('dictionary-feedback--component')
2120					.hide();
2121				// title
2122				var $title = $(document.createElement('div'))
2123					.addClass('dictionary-feedback--title')
2124					.html(__('dictionaries', 'feedback') + ' <span class="dictionary-feedback--searchWord">\'' + word_data.SearchWord + '\'</span>');
2125				// content
2126				var $content = $(document.createElement('div'))
2127					.addClass('dictionary-feedback--content');
2128				// info
2129				var $info = $(document.createElement('div'))
2130					.addClass('dictionary-feedback--info')
2131					.html(__('dictionaries', 'feedback_info')
2132						.replace('{dictionary_title}', '<b>' + Dictionary.searchData.dictionary.Title + '</b>')
2133						.replace('{dictionary_owner}', '<a target="_blank" href="' + Dictionary.searchData.dictionary.OwnerUrl + '">' + Dictionary.searchData.dictionary.Owner + '</a>')
2134					);
2135				// form
2136				var $form = $(document.createElement('form'))
2137					.attr('method', 'post')
2138					.attr('action', '/')
2139					.addClass('dictionary-feedback--form')
2140					.submit(function (e) {
2141						var $this = $(this);
2142						e.preventDefault();
2143						if (!$this.find('.dictionary-feedback--submit').hasClass('busy')) {
2144							if (Validator.validate($this)) {
2145								$this.find('.dictionary-feedback--submit').addClass('busy');
2146								$.post('/dictionary_feedback_do.php', $this.serialize(), function () {
2147									$word_actions_data_holder.find('.dictionary-feedback--component').slideUp(function () {
2148										var $this = $(this);
2149										var $feedback_confirmation = $(document.createElement('div'))
2150											.addClass('dictionary-feedback--confirmation');
2151										var $feedback_confirmation_text = $(document.createElement('div'))
2152											.text(__('dictionaries', 'feedback_confirmation'));
2153										var $feedback_confirmation_closeButton = $(document.createElement('div'))
2154											.addClass('button dictionary-feedback--close-button')
2155											.text(__('dictionaries', 'close'))
2156											.on('click', function () {
2157												$word.find('.dictionary-results--word-icon--feedback').removeClass('dictionary-results--word-icon--active');
2158												$word_actions_data_holder.find('.dictionary-feedback--component').slideUp(function () {
2159													$this.remove();
2160												});
2161											});
2162										$feedback_confirmation.append($feedback_confirmation_text);
2163										$feedback_confirmation.append($feedback_confirmation_closeButton);
2164										$this.empty().append($feedback_confirmation);
2165										$this.slideDown();
2166									});
2167								});
2168							}
2169						}
2170					});
2171				// dictionary id
2172				var $dictionaryId = $(document.createElement('input'))
2173					.attr('type', 'hidden')
2174					.attr('name', 'DictionaryId')
2175					.val(Tools.getQueryVariable('_DictionaryId'));
2176				var $wordId = $(document.createElement('input'))
2177					.attr('type', 'hidden')
2178					.attr('name', 'WordId')
2179					.val(word_data.Id);
2180				// your comments
2181				var $comments = $(document.createElement('textarea'))
2182					.attr('name', 'Comments')
2183					.attr('placeholder', __('dictionaries', 'your_comment'))
2184					.attr('data-required', 'true')
2185					.addClass('dictionary-feedback--comment');
2186				// your email
2187				var $email = $(document.createElement('input'))
2188					.attr('type', 'text')
2189					.attr('name', 'Email')
2190					.attr('placeholder', __('dictionaries', 'your_email'))
2191					.attr('data-required', 'true')
2192					.attr('data-type', 'email')
2193					.val(Ease.userEmail)
2194					.addClass('dictionary-feedback--email');
2195				// your name
2196				var $name = $(document.createElement('input'))
2197					.attr('type', 'text')
2198					.attr('name', 'Name')
2199					.attr('placeholder', __('dictionaries', 'your_name'))
2200					.attr('data-required', 'true')
2201					.val(Ease.userName)
2202					.addClass('dictionary-feedback--name');
2203				// submit button
2204				var $submit = $(document.createElement('button'))
2205					.attr('type', 'submit')
2206					.addClass('button dictionary-feedback--submit')
2207					.html(__('dictionaries', 'send_to_dictionary_owner')
2208						.replace('{dictionary_owner}', Dictionary.InflectOwner(Dictionary.searchData.dictionary.Owner))
2209					);
2210
2211				// append elements
2212				$content.append($info);
2213				$form
2214					.append($dictionaryId)
2215					.append($wordId)
2216					.append($comments)
2217					.append($email)
2218					.append($name)
2219					.append($submit);
2220				$content.append($form);
2221				$container.append($title);
2222				$container.append($content);
2223				$word_actions_data_holder.append($container);
2224				$word_actions_data_holder.find('.dictionary-feedback--component').slideDown();
2225			} else {
2226				$word.find('.dictionary-results--word-icon--feedback').removeClass('dictionary-results--word-icon--active');
2227				$word_actions_data_holder.find('.dictionary-feedback--component').slideUp(function () {
2228					$(this).remove();
2229				});
2230			}
2231		}
2232	},
2233
2234	Spellchecker: {
2235		Init: function () {
2236
2237			// Cache jquery selectors
2238			var $word = null;
2239			var $body = $('body');
2240			var $dictionarySpellcheckerTextholder = $('#dictionary-spellchecker--textholder');
2241			var $dictionarySpellcheckerEditor = $('#dictionary-spellchecker--editor');
2242			var $dictionarySpellcheckerReadspeaker = $('#dictionary-spellchecker--readspeaker');
2243			var $dictionarySpellcheckerListenButton = $('#dictionary-spellchecker--listen-button');
2244			var $dictionarySpellcheckerCheckSpellingButton = $('#dictionary-spellchecker--check-spelling-button');
2245			var $dictionarySpellcheckerContextMenu = $('#dictionary-spellchecker--context-menu');
2246
2247
2248			// Load text from session storage onload
2249			$dictionarySpellcheckerTextholder.val(sessionStorage.getItem('text') ? sessionStorage.getItem('text') : '');
2250			$dictionarySpellcheckerEditor.html($dictionarySpellcheckerTextholder.val().replace(/\n/g, '<br>'));
2251
2252
2253			// Listen for key-presses, and update the hidden textarea on changes
2254			$dictionarySpellcheckerEditor.on('keypress keydown keyup change', function (e) {
2255				var before = $dictionarySpellcheckerTextholder.val();
2256				$dictionarySpellcheckerTextholder.val($dictionarySpellcheckerEditor.html().replace(/<br>/g, "\r\n").replace(/<.*?>/g, '').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&'));
2257				if (before !== $dictionarySpellcheckerTextholder.val()) {
2258					$dictionarySpellcheckerCheckSpellingButton.prop('disabled', false);
2259				}
2260			});
2261
2262
2263			// Listen for copy and cut events, and sanitize content
2264			/*$dictionarySpellcheckerEditor.on('copy cut', function (e) {
2265				var copiedtext = '';
2266				var range = null;
2267				var selection = null;
2268				e.preventDefault();
2269				if (e.originalEvent.clipboardData) {
2270					// OTHER BROWSERS
2271					range = document.createRange();
2272					range.selectNodeContents($dictionarySpellcheckerEditor[0]);
2273					selection = window.getSelection();
2274					selection.removeAllRanges();
2275					selection.addRange(range);
2276					copiedtext = $dictionarySpellcheckerTextholder.val();
2277					e.originalEvent.clipboardData.setData('text/plain', copiedtext.replace(/\n/g, "\r\n"));
2278				} else {
2279					// IE
2280					try {
2281						$dictionarySpellcheckerTextholder.select();
2282						var execCommandResponse = document.execCommand("copy");
2283						range = document.createRange();
2284						range.selectNodeContents($dictionarySpellcheckerEditor[0]);
2285						selection = window.getSelection();
2286						selection.removeAllRanges();
2287						selection.addRange(range);
2288						return execCommandResponse;
2289					} catch (ex) {
2290						console.warn("Copy to clipboard failed.", ex);
2291						return false;
2292					} finally {
2293						//document.body.removeChild(textarea);
2294					}
2295				}
2296				if (e.type === 'cut') {
2297					$dictionarySpellcheckerEditor.empty();
2298				}
2299			});*/
2300
2301
2302			// Listen for paste events, and manually handle pasting, and update the hidden textarea on changes
2303			$dictionarySpellcheckerEditor.on('paste', function (e) {
2304				e.preventDefault();
2305				var pastedText = '';
2306				if (e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData) {
2307					// OTHERS BROWSERS
2308					pastedText = e.originalEvent.clipboardData.getData('text/plain');
2309					document.execCommand("insertText", false, pastedText);
2310				} else if (window.clipboardData && window.clipboardData.getData) {
2311					// IE
2312					pastedText = window.clipboardData.getData('Text');
2313					var selection;
2314					var range;
2315					if (window.getSelection) {
2316				selection = window.getSelection();
2317				if (selection.getRangeAt && selection.rangeCount) {
2318					range = selection.getRangeAt(0);
2319					range.deleteContents();
2320					var div = document.createElement('div');
2321					div.innerHTML = pastedText.replace(/\r?\n/g, '<br>');
2322					var frag = document.createDocumentFragment();
2323					var node;
2324					var lastNode;
2325					while ((node = div.firstChild)) {
2326						lastNode = frag.appendChild(node);
2327					}
2328					range.insertNode(frag);
2329
2330					// Set caret after
2331					if (lastNode) {
2332						range = range.cloneRange();
2333						range.setStartAfter(lastNode);
2334						range.collapse(true);
2335						selection.removeAllRanges();
2336						selection.addRange(range);
2337					}
2338
2339				}
2340					} else {
2341						$dictionarySpellcheckerEditor.text(pastedText);
2342					}
2343				}
2344				$dictionarySpellcheckerTextholder.val($dictionarySpellcheckerEditor.html().replace(/<br>/g, "\r\n").replace(/<\/p>/g, "</p>\r\n").replace(/<.*?>/g, '').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&'));
2345				$dictionarySpellcheckerCheckSpellingButton.click();
2346			});
2347
2348
2349			// Listen for contextmenu on not-found and partially found words, and inject own menu
2350			$body.on('contextmenu', '.spellchecker--word--not-found, .spellchecker--word--partial', function (e) {
2351				e.preventDefault();
2352				if (window.getSelection) {
2353					document.getSelection().removeAllRanges();
2354				}
2355				$word = $(this);
2356				// Show spinner
2357				$dictionarySpellcheckerContextMenu.html('<div style="text-align: center; padding-top: 3px"><img src="/ease/images/loader_1_16x16.gif"></div>');
2358				// Set context-menu postition
2359				$dictionarySpellcheckerContextMenu.css({
2360					top:  (e.offsetY - $dictionarySpellcheckerEditor.scrollTop()) + 'px',
2361					left: (e.offsetX - $dictionarySpellcheckerEditor.scrollLeft()) + 'px'
2362				});
2363				// Show context-menu
2364				$dictionarySpellcheckerContextMenu.show();
2365				// Get list of similar words using ajax
2366				$.get('https://stava.sprotin.fo/api/get_similar_words_json.php', {
2367					searchword: $word.text(),
2368					case: $word.hasClass('spellchecker--word--first-word') ? 'any' : 'word'
2369				}, function (data) {
2370					// Create html for context-menu
2371					var html = '<ul class="dictionary-spellchecker--context-menu-items">';
2372					//if ($word.hasClass('spellchecker--word--uppercase') && !$word.hasClass('spellchecker--word--first-word')) {
2373					//	html += '<li class="dictionary-spellchecker--context-menu-item">' + $word.text().toLowerCase() + '</li>';
2374					//}
2375					html += '<li class="dictionary-spellchecker--context-menu-button dictionary-spellchecker--context-menu-button--copy-word">Avrita orðið</li>';
2376					if (data.Words.length) {
2377						data.Words.forEach(function (row) {
2378							html += '<li class="dictionary-spellchecker--context-menu-item">' + ($word.hasClass('spellchecker--word--first-word') ? (row.Word.substring(0, 1).toUpperCase() + row.Word.substring(1)) : row.Word) + '</li>';
2379						});
2380					} else {
2381						html += '<div class="dictionary-spellchecker--context-menu-message">Eingin líknandi orð funnin</div>';
2382					}
2383					html += '</ul>';
2384					$dictionarySpellcheckerContextMenu.html(html);
2385				}, 'json');
2386				// Prevent standard context menu
2387				return false;
2388			});
2389
2390
2391			// Listen for contextmenu on wrong-case words, and inject own menu
2392			$body.on('contextmenu', '.spellchecker--word--wrong-case', function (e) {
2393				e.preventDefault();
2394				if (window.getSelection) {
2395					document.getSelection().removeAllRanges();
2396				}
2397				$word = $(this);
2398				// Create html for context-menu
2399				var html = '<ul class="dictionary-spellchecker--context-menu-items">';
2400				html += '<li class="dictionary-spellchecker--context-menu-item">' + $word.text().charAt(0).toUpperCase() + $word.text().substr(1) + '</li>';
2401				html += '</ul>';
2402				$dictionarySpellcheckerContextMenu.html(html);
2403				// Set context-menu postition
2404				$dictionarySpellcheckerContextMenu.css({
2405					top:  (e.offsetY - $dictionarySpellcheckerEditor.scrollTop()) + 'px',
2406					left: (e.offsetX - $dictionarySpellcheckerEditor.scrollLeft()) + 'px'
2407				});
2408				// Show context-menu
2409				$dictionarySpellcheckerContextMenu.show();
2410				// Prevent standard context menu
2411				return false;
2412			});
2413
2414
2415			// Hide context-menu on click
2416			$body.on('click', function (e) {
2417				$dictionarySpellcheckerContextMenu.hide();
2418			});
2419
2420
2421			// Replace word with similar word (or uppercase) on context-menu click
2422			$body.on('click', '.dictionary-spellchecker--context-menu-item', function (e) {
2423				var $this = $(this);
2424				$word.text($this.text());
2425				$word.attr('class', 'spellchecker--word spellchecker--word--found');
2426				$dictionarySpellcheckerTextholder.val($dictionarySpellcheckerEditor.html().replace(/<br>/g, "\r\n").replace(/<.*?>/g, '').replace(/&nbsp;/g, ' ').replace(/&amp;/g, '&'));
2427				$dictionarySpellcheckerCheckSpellingButton.click();
2428			});
2429
2430
2431			// Copy word on context-menu click
2432			$body.on('click', '.dictionary-spellchecker--context-menu-button--copy-word', function (e) {
2433				e.preventDefault();
2434				Tools.copyToClipboard($word.text());
2435			});
2436
2437
2438			// Add shortcut alt-K to check the spelling
2439			$(window).on('keydown', function (_e) {
2440				var keyCode = _e.keyCode || _e.which;
2441				if (_e.altKey && keyCode === 75) {
2442					$dictionarySpellcheckerCheckSpellingButton.click();
2443				}
2444			});
2445
2446
2447			// Listen for clicks on check text spelling button
2448			$dictionarySpellcheckerCheckSpellingButton.on('click', function () {
2449				window.rs && window.rs.PlayerAPI && window.rs.PlayerAPI.stop();
2450				$dictionarySpellcheckerReadspeaker.removeClass('rsexpanded rsbtn rspaused rsplaying');
2451				sessionStorage.setItem('text', $dictionarySpellcheckerTextholder.val());
2452				$.post('https://stava.sprotin.fo/api/check_spelling_json.php', {
2453					text: $dictionarySpellcheckerTextholder.val()
2454				}, function (data) {
2455					if (data.status !== 'success') {
2456						alert('Error (1): ' + data.message);
2457					} else {
2458						//location.reload();
2459						$dictionarySpellcheckerEditor.html(data.html);
2460						$dictionarySpellcheckerCheckSpellingButton.prop('disabled', true);
2461					}
2462				}, 'json')
2463			});
2464
2465
2466			// Listen for clicks on the listen button
2467			$dictionarySpellcheckerListenButton.on('click', function () {
2468				var domain = 'https://app-eu.readspeaker.com/cgi-bin/rsent';
2469				var customerId = 7214;
2470				var lang = 'fo_fo';
2471				var voice = 'hanus22k';
2472				var url = domain + '?customerid=' + customerId + '&lang=' + lang + '&readid=dictionary-spellchecker--editor&voice=' + voice + '&url=' + encodeURIComponent('https://sprotin.fo/readspeaker.php');
2473				//noinspection JSUnresolvedFunction
2474				//readpage(url, 'dictionary-spellchecker--readspeaker');
2475			});
2476
2477
2478			// Check text on load
2479			$dictionarySpellcheckerCheckSpellingButton.click();
2480
2481		}
2482	},
2483};

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.