PageSourceSearch

https://dr-tentaculus.github.io/magic-items/js/script.js?v=0.5

js dr-tentaculus.github.io collected 2026-10-03 09:03:49 UTC 54,198 bytes, 1,664 lines download raw bytes

1var TENTACULUS_APP_VERSION = "1.0.0";
2
3var oConfig = {}; // global app config data
4function setConfig(prop, val) {
5	if(prop && val != undefined && oConfig) {
6		oConfig[prop] = val;
7		localStorage.setItem("config", JSON.stringify(oConfig));
8	}
9}
10function getConfig(prop) {
11	oConfig = JSON.parse(localStorage.getItem("config")) || {};
12	if(prop!=undefined) {
13		return localStorage.getItem("config")? oConfig[prop] : null;
14	}
15	return ""; //oConfig;
16}
17
18function randd(min, max) {
19  return Math.floor(arguments.length > 1 ? (max - min + 1) * Math.random() + min : (min + 1) * Math.random());
20};
21function shuffle(o){
22	if (o) {
23		if ((o.length == undefined || typeof o != 'object'))
24		  return [0];
25		for(var j, x, k = o.length; k; j = Math.floor(Math.random() * k), x = o[--k], o[k] = o[j], o[j] = x);
26	}
27    return o;
28};
29window.onload = function(){
30	var fCtrlIsPressed = false;
31
32	var oTimer; // for TimeOut (filtering)
33	var nTimerSeconds = 100;
34
35	var aHiddenItems = [];
36	var aLockedItems = {};
37	var filteredItems = [];
38
39	var oSource = {};
40
41	function arrDiff(arr1, arr2) {
42		var arr3 = arr2.map(function(item){return item.en});
43		return arr1.filter(
44			function(item){
45				return (arr3.indexOf(item.en.name)>=0)? false: true;
46			}
47		);
48	}
49
50	function removeFromArr(arr, el) {
51		var index;
52
53		for (var i=0; i<arr.length; i++) {
54			if(arr[i] == el) {
55				index = i;
56				break;
57			}
58		}
59		arr.splice(i, 1);
60		return arr
61	}
62
63	function getViewPortSize(mod) {
64		var viewportwidth;
65		var viewportheight;
66
67		//Standards compliant browsers (mozilla/netscape/opera/IE7)
68		if (typeof window.innerWidth != 'undefined')
69		{
70			viewportwidth = window.innerWidth,
71			viewportheight = window.innerHeight
72		}
73
74		// IE6
75		else if (typeof document.documentElement != 'undefined'
76		&& typeof document.documentElement.clientWidth !=
77		'undefined' && document.documentElement.clientWidth != 0)
78		{
79			viewportwidth = document.documentElement.clientWidth,
80			viewportheight = document.documentElement.clientHeight
81		}
82
83		//Older IE
84		else
85		{
86			viewportwidth = document.getElementsByTagName('body')[0].clientWidth,
87			viewportheight = document.getElementsByTagName('body')[0].clientHeight
88		}
89
90		if(mod=="width")
91			return viewportwidth;
92
93		return viewportwidth + "~" + viewportheight;
94	}
95
96	function createSelect(src, params) {
97		var options = "";
98		var selected_key = params.selected_key;
99		var id = params.id? "id='"+params.id+"'" : "";
100		var sClass = params.controlClass? params.controlClass : "";
101		var atr_class = params.class? params.class : "";
102		var width = params.width? "; width: "+ params.width: "";
103		var lableText;
104		var min_width = 0;
105		var oParams = params.params;
106		var aParams = [], sParams="";
107		if(oParams) {
108			oParams.forEach(function(item) {
109				aParams.push(item.name+"='"+item.value+"'");
110			});
111			sParams = aParams.join(" ");
112		}
113		if(Array.isArray(src)) {
114			src.forEach(function(item){
115				var key = item.name;
116				var text = item.title;
117				if(text.length > min_width)
118					min_width = text.length/2;
119				options += "<li class='option' data-key='"+key+"'>"+text+"</li>";
120				if(key == selected_key){
121					lableText = text
122				}
123			});
124		} else {
125			for(item in src){
126				var key = item;
127				var text = src[item].ru.title;
128				if(text.length > min_width)
129					min_width = text.length/2;
130				options += "<li class='option' data-key='"+key+"'>"+text+"</li>";
131				if(key == selected_key){
132					lableText = text
133				}
134			};
135		}
136		min_width = min_width>20? 20: min_width;
137		min_width = min_width<5? 5: min_width;
138		min_width = ~~(min_width*0.75);
139
140		var list = "<ul class='list'>" + options + "</ul>";
141
142		var selectedKey = selected_key;
143		//var label="<div class='label"+atr_class+"' data-selected-key='" + selectedKey + "'>" + lableText + "</div>";
144		var label="<div class='label' data-selected-key='" + selectedKey + "'>" + lableText + "</div>";
145		//var select = "<button " + id + " " + sParams + " class='customSelect "+sClass+"' >" + label + list + "</button>";
146		var select = "<button " + id + " class='customSelect' >" + label + list + "</button>";
147
148		return select;
149	}
150
151	function createComboBox(src, param) {
152		var ARR_DOWN = '<i class="fa fa-arrow-down"></i>';
153		var ARR_UP = '<i class="fa fa-arrow-up"></i>';
154		var ret = '';
155		var id =  param.id? "id='"+param.id+"'": "";
156		var title = param.title? param.title: "Выберите";
157		var checked = param.checkAll? "checked": "";
158		var isOpen = (param.isOpen!=undefined) ? param.isOpen : true;
159		var arrow, display = "", content_open=true;
160		var min_width = 0;
161		if(isOpen && isOpen != "false"){
162			arrow="<div class='combo_box_arrow'><span class='arr_down' style='display:none'>"+ARR_DOWN+"</span><span class='arr_up'>
162"+ARR_UP+"</span></div>";
163		} else {
164			arrow="<div class='combo_box_arrow'><span class='arr_down'>"+ARR_DOWN+"</span><span class='arr_up' style='display:none'>"+ARR_UP+"</span></div>";
165			display = " style='display:none' ";
166			content_open = false;
167		}
168		if(Array.isArray(src)) {
169			for (var i =0; i < src.length; i++) {
170				var type = src[i];
171				var max = Math.max(type.en.length, type.ru.length)/2;
172				if (max > min_width) {
173					min_width = max;
174				}
175
176				var sOptionValue = type.key? type.key : type.en;
177
178				ret+="<input "+checked+" type='checkbox' value='"+sOptionValue+"' id='ch_"+sOptionValue.replace(" ", "_")+"'><label for='ch_"+sOptionValue.replace(" ", "_")+"' data-hierarchy='root'>"+type.en+"<br>"+type.ru+"</label>";
179
180			}
181		} else {
182			for(key in src) {
183				var type = src[key];
184				var max = Math.max(type.text.en.title.length, type.text.ru.title.length)/2;
185				if (max > min_width) {
186					min_width = max;
187				}
188
189				var sOptionValue = key;
190
191				ret+="<input "+checked+" type='checkbox' value='"+sOptionValue+"' id='ch_"+sOptionValue.replace(" ", "_")+"'><label for='ch_"+sOptionValue.replace(" ", "_")+"' data-hierarchy='root'>"+type.text.en.title+"<br>"+type.text.ru.title+"</label>";
192			}
193		}
194
195		min_width = min_width>20? 20: min_width;
196		min_width = min_width<5? 5: min_width;
197		min_width = ~~(min_width*0.9)+2;
198		ret = "<div "+id+" class='combo_box' data-text='"+title+"' data-content-open='"+content_open+"'><div class='combo_box_title'>"+title+"</div><div class='combo_box_content' "+display+" >"+ret+"</div>"+arrow+"</div>";
199		return ret;
200	}
201
202	function createInput(params){
203		var id = params.id? "id='"+params.id+"'" : "";
204		return "<div "+id+" class='customInput'><input type='text'><span class='cross'></span></div>";
205	}
206
207	function showInfoWin(sText) {
208		$(".mod_win_wrapper").remove();
209		var bCross = "<span class='bCloseInfoWin'>×</span>";
210		$("body").append("<div class='mod_win_wrapper'><div class='mod_win'>"+bCross+sText+"</div></div>");
211    $("body").css("overflow-y", "hidden");
212		$(".mod_win_wrapper").fadeIn();
213	}
214	function hideInfoWin() {
215		if($(".mod_win_wrapper").length){
216			$.when($(".mod_win_wrapper").fadeOut()).done(function(){
217        $("body").css("overflow-y", "auto");
218      });
219		}
220	}
221	function showDBG() {
222		if(!$("#dbg").length){
223			$("body").append("<div id='dbg'></div>");
224		}
225		$("#dbg").fadeIn();
226		$("body").height();
227	}
228	function hideDBG() {
229		if($("#dbg")){
230			$("#dbg").fadeOut();
231		}
232	}
233
234	function pretifyString(s) {
235		return s.substr(0,1).toUpperCase() + s.substr(1);
236	}
237
238	function getItemAttr(oItem, sAttr, sLang) {
239    try{
240      if(oItem[sLang] && oItem[sLang][sAttr] != undefined && oItem[sLang][sAttr] != ""){
241        return oItem[sLang][sAttr];
242      }
243      var aLang = [];
244      for (lang in oItem){
245        aLang.push(lang);
246      }
247      for(var i=0; i<aLang.length; i++){
248        if(oItem[aLang[i]][sAttr] != undefined) {
249          return oItem[aLang[i]][sAttr];
250        }
251      }
252    } catch(err){
253      console.log(err);
254      console.log(oItem.en.name);
255    }
256		return "";
257	}
258	function getItemAttrFromDB(oDataSource, oParam) {
259    var aParam = [], aReturn = [];
260    if(Array.isArray(oParam.attr)){
261      aParam = oParam.attr;
262    } else {
263      aParam = [oParam.attr];
264    }
265    for(var i=0; i<aParam.length; i++) {
266      var sAttr = (aParam[i]!=undefined)? String(aParam[i]).toLowerCase().trim() : undefined;
267      var sLang = (oParam.lang!=undefined)? String(oParam.lang).toLowerCase().trim() : undefined;
268      var sSubAttr = oParam.subattr || "title";
269      if(oDataSource[sAttr]){
270        if(oDataSource[sAttr].text[sLang]){
271          aReturn.push(oDataSource[sAttr].text[sLang][sSubAttr] || oDataSource[sAttr].text[sLang].title);
272          continue;
273        }
274
275        var aLang = [];
276        for (lang in oDataSource[sAttr]){
277          aLang.push(lang);
278        }
279        for(var i=0; i<aLang.length; i++){
280          if(oDataSource[sAttr].text[aLang[i]]) {
281            aReturn.push(oDataSource[sAttr].text[aLang[i]][sSubAttr] || oDataSource[sAttr].text[aLang[i]].title);
282            break;
283          }
284        }
285      }
286    }
287
288    return aReturn.join(", ");
289	}
290
291	function prepareRandomProps(sText){
292		var sButton = "<button class='randomPropButton'>🎲</button>";
293		
294		sText = sText.replace(/((\d) мал[а-я]+ положитель[а-я]+ свойст[а-я]+)/ig, "<span data-count='$2' data-kind='minorBenefit' class='randomProp'>$1</span> "+sButton+"");
295		sText = sText.replace(/((\d) основ[а-я]+ положитель[а-я]+ свойст[а-я]+)/ig, "<span data-count='$2' data-kind='majorBenefit' class='randomProp'>$1</span> "+sButton+"");
296		sText = sText.replace(/((\d) мал[а-я]+ отрицатель[а-я]+ свойст[а-я]+)/ig, "<span data-count='$2' data-kind='minorDetrim' class='randomProp'>$1</span> "+sButton+"");
297		sText = sText.replace(/((\d) основ[а-я]+ отрицатель[а-я]+ свойст[а-я]+)/ig, "<span data-count='$2' data-kind='minorDetrim' class='randomProp'>$1</span> "+sButton+"");
298		
299		sText = sText.replace(/((\d) minor beneficial propert[a-z]+)/ig, "<span data-count='$2' data-kind='minorBenefit' class='randomProp'>$1</span> "+sButton+"");
300		sText = sText.replace(/((\d) major beneficial propert[a-z]+)/ig, "<span data-count='$2' data-kind='majorBenefit' class='randomProp'>$1</span> "+sButton+"");
301		sText = sText.replace(/((\d) minor detrimental propert[a-z]+)/ig, "<span data-count='$2' data-kind='minorDetrim' class='randomProp'>$1</span> "+sButton+"");
302		sText = sText.replace(/((\d) major detrimental propert[a-z]+)/ig, "<span data-count='$2' data-kind='minorDetrim' class='randomProp'>$1</span> "+sButton+"");
303		
304		return sText;
305	}
306	
307	function createCard(oItem, lang, sLockedItem, sView) {
308		if (oItem[lang] || (lang="en", oItem[lang])) {
309			var o = oItem[lang];
310			var s_name = getItemAttr(oItem, "name", lang);
311			var s_img = getItemAttr(oItem, "img", lang);
312			var s_type = getItemAttrFromDB(oTypes, {attr: getItemAttr(oItem, "type", lang), lang: lang});
313			var s_gender = getItemAttrFromDB(oTypes, {attr: getItemAttr(oItem, "type", lang), subattr: "gender", lang: lang});
314			var s_rariry = getItemAttrFromDB(oRarity, {attr: getItemAttr(oItem, "rarity", lang), subattr: s_gender, lang: lang});
315			var s_attunement = getItemAttr(oItem, "attunement", lang);
316      var s_typeAdditions = getItemAttr(oItem, "typeAdditions", lang);
317			var s_notes = getItemAttr(oItem, "notes", lang);
318			var s_text = prepareRandomProps(getItemAttr(oItem, "text", lang).split("<br>").map(item => "<p>"+item+"</p>").join(""));
319			var s_source = getItemAttr(oItem, "source", "en");
320			var s_sourcePage = getItemAttr(oItem, "sourcePage", lang);
321      var fText = (sView == 'text');
322      
323      var s_rarity_class = getItemAttrFromDB(oRarity, {attr: getItemAttr(oItem, "rarity", "en"), subattr: s_gender, lang: "en"}).toLowerCase().replace(" ", "_").trim();
324
325      var s_coast = getItemAttr(oItem, "coast", lang) ||
326        oRarity[oItem.en.rarity] && oRarity[oItem.en.rarity].coast ||
327        "";
328      if(s_coast){
329        s_coast = "<div class='coast'><div class='coin'>"+s_coast+"</div></div>";
330      }
331      try{
332        
333        var oImg = "<img class='img' src='img/items/min_200/"+s_img+"'>";
334        if(!s_img) {
335          oImg = "<img class='img' src='img/items/placeholder/"+oTypes[oItem.en.type.toLowerCase()].img+"'>";
336          s_img = "img/items/placeholder/"+oTypes[oItem.en.type.toLowerCase()].img;
337        } else{
338          s_img = "img/items/min_200/"+s_img
339        }
340      } catch(err){
341        console.log(s_name);
342      }
343      
344
345
346			var bHideItem = '<span class="bHideItem" title="Скрыть предмет (будет внизу панели фильтров)"><i class="fa fa-eye-slash" aria-hidden="true"></i></span>';
347			var bLockItem = sLockedItem? '<span class="bUnlockItem" title="Открепить обратно"><i class="fa fa-unlock-alt" aria-hidden="true"></i></span>' : '<span class="bLockItem" title="Закорепить предмет (не будут действовать фильтры)"><i class="fa fa-lock" aria-hidden="true"></i></span>';
348			var textSizeButtons = "<div class='sizeButtonsContainer noprint'><a href='#' class='textMin' title='Уменьшить размер текста'>–</a><a href='#' class='textMax' title='Увеличить размер текста'>+</a></div>";
349
350			sLockedItem = sLockedItem? " lockedItem " : "";
351
352			var cardWidth = getConfig("cardWidth");
353			var style = "";
354			if(cardWidth && !fText) {
355				var style = " style='width: " + cardWidth + "' ";
356			}
357
358			var sNeedHelp = (lang == "ru")?  getItemAttr(oItem, "name", "en") : getItemAttr(oItem, "name", "ru");
359      var sImg = fText? "" :'style="background-image: url('+s_img+');"';
360      //s_text = fText? s_text.split("<br>").map(item => "<p>"+item+"</p>").join(""): s_text;
361
362			ret = '<div class="cardContainer '+(fText? "textView " : "") + sLockedItem + " " + s_rarity_class +'" '+ style +' data-name="' + oItem.en.name + '"  data-name-ru="' + oItem.ru.name + '"  data-lang="' + lang + '">'+
363				'<div class="ItemCard">'+
364					'<div class="content" '+sImg+'>'+
365            bLockItem +
366            bHideItem +
367            "<div class='header_info'>"+
368              '<h1 title="'+s_name+(sNeedHelp?" ("+sNeedHelp+")":"")+'">' +s_name+ '</h1>'+
369              '<div class="subtitle">' + s_rariry + " " + s_type+  " " + s_typeAdditions+  " " + s_attunement + '</div>'+
370            "</div>"+
371            "<div class='info'>"+
372              oImg+
373              '<div class="text">' + s_text + '</div>	'+
374              textSizeButtons +
375            "</div>"+
376            s_coast+ 
377            '<span class="sf_text"> <i class="fa fa-info-circle" aria-hidden="true"></i></span>'+
378						"<div class='source' title=\"Источник: "+ oSources[s_source].text[lang].title+"\">"+ s_source+"</div>"+
379					'</div>'+
380				'</div>'+
381			'</div>';
382			return ret;
383		} else {
384			console.log("not found: ");
385			console.dir(oItem);
386		}
387	}
388
389
390	// function createItemsIndex() {
391	// 	var Items = "";
392	// 	allItems.forEach(function(item) {
393	// 		Items += createCard(item);
394	// 	});
395	// 	$(".ItemContainer").html(Items);
396	// 	$("#before_Items").hide();
397	// 	$("#info_text").hide();
398	// }
399	function showFiltered(oParams) {
400		try{
401			var sName = oParams.sName;
402			var aSources = oParams.aSources;// && oParams.aSources.split(",").map(item => item.trim());
403			var aRarity = oParams.aRarity && oParams.aRarity.split(",").map(item => item.trim());
404			var aTypes = oParams.aTypes && oParams.aTypes.split(",").map(item => item.trim());
405			var sLang = oParams.sLang;
406			var sView = oParams.sView;
407			var sSort = oParams.sSort;
408      var fRandom = oParams.fRandom;
409		} catch (err) {
410			console.dir(oParams);
411		}
412
413		 var fHiddenItems = (aHiddenItems.length>0)? true: false;
414		 var fLockedItems = (aLockedItems.length>0)? true: false;
415
416		$(".ItemContainer").empty();
417		var Items = "";
418
419
420		filteredItems = allItems; //[]; //arrDiff(filteredItems, aHiddenItems);
421
422
423		// name
424		if (sName) {
425			sName = sName.toLowerCase().trim();
426			filteredItems = filteredItems.filter(function(Item){
427				return (
428					(Item.en.name.toLowerCase().trim().indexOf(sName)>=0) || 
429					(Item.ru && Item.ru.name.toLowerCase().trim().indexOf(sName)>=0) ||
430					(Item.ru && Item.ru.nic && Item.ru.nic.toLowerCase().trim().indexOf(sName)>=0)					
431					);
432			});
433		}
434
435		//types
436		if(aTypes && aTypes.length>0) {
437			filteredItems = filteredItems.filter(function(Item){
438				for(var i = 0; i < aTypes.length; i++) {
439					if(aTypes[i].toLowerCase().trim() == Item.en.type.toLowerCase().trim()) {
440						return true;
441					}
442				}
443				return false;
444			});
445		}
446
447		//rarity
448		if(aRarity && aRarity.length>0) {
449			filteredItems = filteredItems.filter(function(Item){
450				for(var i = 0; i < aRarity.length; i++) {
451					if(aRarity[i].toLowerCase().trim() == String(Item.en.rarity).toLowerCase().trim() || aRarity[i].toLowerCase().trim() == 0) {
452						return true;
453					}
454				}
455				return false;
456			});
457		}
458
459		//source
460		if(aSources && aSources.length>0 && aSources.length<9) {
461			filteredItems = filteredItems.filter(function(Item){
462				for(var i = 0; i < aSources.length; i++) {
463          try{
464            if(aSources[i].toLowerCase().trim() == Item.en.source.toLowerCase().trim()) {
465              return true;
466            }
467          } catch (err) {
468            console.dir(err);
469            console.dir(Item.en);
470          }
471				}
472				return false;
473			});
474		}
475
476
477
478		filteredItems = fHiddenItems? arrDiff(filteredItems, aHiddenItems) : filteredItems;
479		//filteredItems = fLockedItems? filteredItems.concat(aLockedItems) : filteredItems;
480		if (fLockedItems) {
481			for (var i = 0; i<allItems.length; i++){
482				for (var j=0; j<aLockedItems.length; j++){
483					if(allItems[i].en.name == aLockedItems[j].en) {
484						filteredItems.push(allItems[i]);
485						break;
486					}
487				}
488			}
489		}
490
491		// sort
492		if(sSort == 'alpha') {
493			filteredItems.sort(function(a, b) {
494				if(a[sLang] && b[sLang]) {
495					if (a[sLang].name.toLowerCase().trim() < b[sLang].name.toLowerCase().trim() )
496						return -1;
497					if (a[sLang].name.toLowerCase().trim() > b[sLang].name.toLowerCase().trim() )
498						return 1;
499				}
500				return 0
501			});
502		} else {
503			filteredItems.sort(function(a, b) {
504				if(a[sLang] && b[sLang]) {
505					if (a.en.rarity+a[sLang].name.toLowerCase().trim() < b.en.rarity+b[sLang].name.toLowerCase().trim() )
506						return -1;
507					if (a.en.rarity+a[sLang].name.toLowerCase().trim() > b.en.rarity+b[sLang].name.toLowerCase().trim() )
508						return 1;
509				}
510				return 0
511			});
512		}
513
514    if(fRandom){
515      filteredItems = [filteredItems[randd(0, filteredItems.length)]];
516      var sName = filteredItems[0].en.name.toLowerCase();
517      $("#NameInput input").val(sName);
518    }
519    
520		for (var i in filteredItems) {
521			if(filteredItems[i]) {
522				var fLocked = filteredItems[i].locked? true: false;
523				var tmp = createCard(filteredItems[i], sLang, fLocked, sView)
524				if (tmp)
525					Items += tmp;
526			}
527		}
528    
529		$(".ItemContainer").html(Items);
530    $(".ItemContainer").attr("data-itemCount", filteredItems.length);
531		$("#before_Items").hide();
532		$("#info_text").hide();
533	}
534
535	function filterItems(oParams){
536		if(!(oParams && oParams.fIgnoreFilters == true)){
537		 var sName = $("#NameInput input").val();
538		 var aTypes = $("#TypeCombobox .combo_box_title").attr("data-val");
539		 var aRarity = $("#RarityCombobox .combo_box_title").attr("data-val");
540		 var aSources = $("#SourceCombobox .combo_box_title").attr("data-val");
541		 	if(aSources) aSources = aSources.split(",").map(function(item){return item.trim()});
542		 var sLang = $("#LangSelect .label").attr("data-selected-key");
543		 var sView = $("#CardViewSelect .label").attr("data-selected-key");
544		 var sSort = $("#SortSelect .label").attr("data-selected-key");
545
546		 var fRandom = (oParams && oParams.fRandom == true)? true: false;
547     
548		 var fHidden = (aHiddenItems.length>0)? true: false;
549		}
550		setConfig("language", sLang);
551		setConfig("view", sView);
552		//setConfig("schoolOpen", $("#SchoolCombobox").attr("data-content-open"));
553		clearTimeout(oTimer);
554		oTimer = setTimeout(function(){
555			showFiltered({
556				sName: sName,
557				aRarity: aRarity,
558				aTypes: aTypes,
559				aSources: aSources,
560				sLang: sLang,
561				sView: sView,
562				sSort: sSort,
563				fHidden: fHidden,
564        fRandom: fRandom
565				});
566		}, nTimerSeconds/4);
567	}
568
569	function createButtons() {
570		var bHome = "<a href='/' class='bt flexChild' title='На главную страницу'><i class='fa fa-home'></i></a>";
571		var bInfo = "<a href='#' class='bt flexChild' id='bInfo' title='Справка'><i class='fa fa-question-circle'></i></a>";
572		var bPrint = "<a href='#' class='bt flexChild' id='bPrint' title='Распечатать'><i class='fa fa-print' aria-hidden='true'></i></a>";
573		$(".p_side").append("<div class='mediaWidth flexParent'>" + bHome + bInfo + bPrint + "</div>");
574	}
575	function createCardWidthButtons() {
576		var label = createLabel("Ширина карточек");
577		var bHome = "<a href='#' class='bt flexChild cardWidthMin' title='Сделать уже'><i class='fa fa-caret-right' aria-hidden='true'></i> <i class='fa fa-caret-left' aria-hidden='true'></i></a>";
578		var bInfo = "<a href='#' class='bt flexChild cardWidthNorm' title='Сделать нормальными'><i class='fa fa-square-o' aria-hidden='true'></i></a>";
579		var bPrint = "<a href='#' class='bt flexChild cardWidthMax' title='Сделать шире'><i class='fa fa-caret-left' aria-hidden='true'></i> <i class='fa fa-caret-right' aria-hidden='true'></i></a>";
580		$(".p_side").append("<div class='mediaWidth flexParent'>" + label + bHome + bInfo + bPrint + "</div>");
581	}
582
583	function createLabel(text) {
584		return "<div class='filterLabel'>"+text+"</div>";
585	}
586
587	function createTypeCombobox(isOpen) {
588		if(isOpen == undefined)
589			isOpen = false;
590		var s1=createComboBox(oTypes, {id: "TypeCombobox", title: "Тип", checkAll: false, isOpen: isOpen});
591		$(".p_side").append("<div class='mediaWidth'>" + s1 + "</div>");
592	}
593	function createRarityCombobox(isOpen) {
594		if(isOpen == undefined)
595			isOpen = false;
596		var s1=createComboBox(oRarity, {id: "RarityCombobox", title: "Редкость", checkAll: false, isOpen: isOpen});
597		$(".p_side").append("<div class='mediaWidth'>" + s1 + "</div>");
598	}
599	function createSourceCombobox(isOpen) {
600		if(isOpen == undefined)
601			isOpen = false;
602		var s1=createComboBox(oSources, {id: "SourceCombobox", title: "Источники", checkAll: false, isOpen: isOpen});
603		$(".p_side").append("<div class='mediaWidth'>" + s1 + "</div>");
604
605		// oSources.forEach(function(el) {
606		// 	oSource[el.key] = el.en;
607		// });
608	}
609	function createNameFilter() {
610    var label = createLabel("Название");
611		var oInput = createInput({id: "NameInput"});
612    var bRandom = "<a href='/#random' class='bt flexChild'  id='bRandom' title='Случайная вещь'>🎲</a>";    
613    var oLine = "<div style='display: flex'>"+oInput + bRandom+"</div>";
614		$(".p_side").append("<div class='mediaWidth'>" + label + oLine + "</div>");
615	}
616  function createAutoSizeTextButton() {
617		var label = createLabel("Размер текста");
618		var bTextSize = "<a href='#' class='bt flexChild cardTestAutoSize' title='Автоподстройка размера текста на карточке'><i class='fa fa-text-height' aria-hidden='true'></i> Рассчитать </a>";
619		$(".p_side").append("<div class='mediaWidth flexParent'>" + label + bTextSize + "</div>");
620	}
621	function createLangSelect(lang) {
622		var src = [
623			{
624				name: "en",
625				title: "English"
626			},
627			{
628				name: "ru",
629				title: "Русский"
630			}
631		];
632		if(!lang)
633			lang = "ru";
634		var Select = createSelect(src, {id: "LangSelect", selected_key: lang, width: "100%"});
635		var label = createLabel("Язык");
636		$(".p_side").append("<div class='mediaWidth'>" + label + Select + "</div>");
637	}
638	function createCardViewSelect(selected) {
639		var src = [
640			{
641				name: "card",
642				title: "Карточки"
643			},
644			{
645				name: "text",
646				title: "Текст"
647			}
648		];
649		if(!selected)
650			selected = "card";
651		var Select = createSelect(src, {id: "CardViewSelect", selected_key: selected, width: "100%"});
652		var label = createLabel("Вид");
653		$(".p_side").append("<div class='mediaWidth'>" + label + Select + "</div>");
654	}
655	function createSortSelect(selected) {
656		var src = [
657			{
658				name: "rarity_alpha",
659				title: "Редкости и алфавиту"
660			},
661			{
662				name: "alpha",
663				title: "Алфавиту"
664			}
665		];
666		if(!selected)
667			selected = "rarity_alpha";
668		var Select = createSelect(src, {id: "SortSelect", selected_key: selected, width: "100%"});
669		var label = createLabel("Сортировать по");
670		$(".p_side").append("<div class='mediaWidth'>" + label + Select + "</div>");
671	}
672
673	function createHiddenItemsList(){
674		if(aHiddenItems.length < 1){
675			$("#HiddenItems").parent().remove();
676			return;
677		}
678		if(!$("#HiddenItems").length>0){
679			var label = createLabel("Скрытые предметы");
680			$(".p_side").append("<div class='mediaWidth'>" + label + "<div id='HiddenItems'></div></div>");
681		}
682		var listHiddenItems = aHiddenItems.map(function(item){
683			return "<a href='#' title='Вернуть на место' class='bUnhideItem' data-name='"+item.en+"'>"+item.ru +" ("+ item.en+") </a>";
684			}).join(" ");
685
686		var bReturnAll = "<a href='#' class='bReturnUnvisible'>Вернуть все обратно</a>";
687		$("#HiddenItems").html(bReturnAll + listHiddenItems);
688	}
689
690	function createLockedItemsArea(){
691    var sView = $("CardViewSelect label").attr("data-selected-key");
692		if(!sView) {
693			let sHash = location.hash;
694			if(sHash && /view=text/i.test(sHash)) {
695				sView="text";
696			}
697		}
698		var aLocked = [];
699		for (var i in aLockedItems){
700			aLocked.push(i);
701		}
702		var aResult = [];
703		var l = aLocked.length;
704		if(l>0){
705			for (var i=0; i<allItems.length; i++) {
706				for (var j=0; j< l; j++) {
707					if(allItems[i].en.name == aLocked[j]) {
708						aResult.push(allItems[i]);
709						aResult[aResult.length-1].lang = aLockedItems[aLocked[j]].lang;
710						//aResult[aResult.length-1].class = aLockedItems[aLocked[j]].class;
711					}
712				}
713			}
714
715			if($("#lockedItemsArea").length<1){
716				$(".p_cont").prepend("<div id='lockedItemsArea'><span class='bUnlockAll'>Открепить все</span><span class='topHeader'></span><div class='content row'></div><span class='bottomHeader'></span></div>");
717
718			}
719			$("#lockedItemsArea .content").html(aResult.sort(function(a, b) {
720				if(a.lang && b.lang) {
721					if (a[a.lang].level+a[a.lang].name.toLowerCase().trim() < b[b.lang].level+b[b.lang].name.toLowerCase().trim() )
722						return -1;
723					if (a[a.lang].level+a[a.lang].name.toLowerCase().trim() > b[b.lang].level+b[b.lang].name.toLowerCase().trim() )
724						return 1;
725				}
726				return 0
727			}).map(function(el){return createCard(el, el.lang, true, sView)}));
728
729			//COUNTER
730			$("#lockedItemsArea .topHeader").html("("+l+")");
731			$(".ItemContainer").addClass("noprint");
732		} else {
733			$("#lockedItemsArea").remove();
734			$(".ItemContainer").removeClass("noprint");
735		}
736	}
737	
738	function createDbButtons() {
739		var sButtons = "<input type='file' style='display: none' id='fileUploader'>"+
740		"<div class='mediaWidth'><button	id='bDownload' class='btn'	>Скачать</button></div>" +
741		"<div class='mediaWidth'><button	id='bUpload' class='btn'	>Загрузить</button></div>";
742    $(".p_side").append("<div class='mediaWidth'>
742" + sButtons + "</div>");
743  }
744
745	function createSidebar() {
746		var lang = getConfig("language");
747		var view = getConfig("view");
748		createButtons();
749		createNameFilter();
750		createTypeCombobox();
751		 createRarityCombobox();
752		 createSourceCombobox();
753		 createCardWidthButtons();
754		 createAutoSizeTextButton();
755		 createLangSelect(lang);
756		 createCardViewSelect(view);
757		 createSortSelect();
758		 createDbButtons();
759
760		$(".p_side").fadeIn();
761	}
762
763
764	/// handlers
765
766	// close Mod Win
767	$("body").on("click", ".bCloseInfoWin", function() {
768		$("#dbg").fadeOut();
769		hideInfoWin();
770	});
771
772	// hide DBG
773	$("body").on("click", "#dbg, .mod_win_wrapper", function() {
774		$("#dbg").fadeOut();
775		hideInfoWin();
776	});
777	$("body").on("click", ".mod_win", function() {
778		//return false;
779	});
780
781	//custom Select
782	$("body").on("click", ".customSelect .label", function() {
783	  if($(this).next(".list").css('display') == 'none') {
784		$(this).parent().focus();
785	  }
786	  $(this).next(".list").fadeToggle();
787	});
788	$("body").on("focusout", ".customSelect", function() {
789	  $(this).find(".list").fadeOut();
790	});
791	$("body").on("click", ".customSelect .option", function() {
792	  var key = $(this).attr("data-key");
793	  var text = $(this).html().replace("<br>", " | ");
794	  $(this).closest(".customSelect").find(".label").attr("data-selected-key", key).text(text);
795	  $(this).parent("ul").fadeOut();
796	  $(this).closest(".customSelect").focusout();
797	  $(this).closest(".customSelect").blur();
798	  //$("#toFocus").focus();
799	});
800
801	// custom Combobox
802	$("body").on('click', ".combo_box_title, .combo_box_arrow", function(){
803		var el = $(this).closest(".combo_box").find(".combo_box_content");
804		if(el.is(":visible"))
805		{
806			el.slideUp();
807			el.next(".combo_box_arrow").find(".arr_down").show();
808			el.next(".combo_box_arrow").find(".arr_up").hide();
809			el.parent().attr("data-content-open", false);
810		}
811		else
812		{
813			el.slideDown();
814			el.next(".combo_box_arrow").find(".arr_down").hide();
815			el.next(".combo_box_arrow").find(".arr_up").show();
816			el.parent().attr("data-content-open", true);
817		}
818	});// get item
819
820	function onSelectItemPress(src) {
821		var d_root='', d_parent='', trig=true;
822
823		var attrFor = src.attr("for"); // $("input#"+attrFor)
824		var oComboBox = src.closest(".combo_box");
825		var sComboBoxId = oComboBox.attr("id");
826		d_root = $("#"+sComboBoxId+" input#"+attrFor).attr("data-root");
827		d_parent = $("#"+sComboBoxId+" input#"+attrFor).attr("data-parent");
828		if($("#"+sComboBoxId+" input#"+attrFor).prop("checked"))
829			{
830			trig=false;
831			}
832		$("#"+sComboBoxId+" input#"+attrFor).prop("checked", trig);
833		/**/
834		if(d_root!='' && d_root!=undefined) {
835			$("#"+sComboBoxId+" input[type=checkbox][data-parent="+d_root+"]").each(function(){
836				$(this).prop( "checked", trig );
837			});
838		}
839		/**/
840		if(d_parent!='' && d_parent!=undefined && trig==false) {
841			$("#"+sComboBoxId+" input[type=checkbox][data-root="+d_parent+"]").prop( "checked", trig);
842
843		}
844
845
846		function make_val(ex, ad, dp){
847			var ret = '';
848			if(dp!=undefined) {
849				ad = dp + " " + ad;
850			}
851			if(ex!=undefined && ex!=""){
852				ret = ex+", "+ad;
853			} else {
854				ret = ad;
855			}
856			return ret;
857		}
858
859		/**/
860		var d_root='';
861		var before_root='';
862		var d_parent='';
863		var txt='';
864		var value='';
865		var title=''
866		$("#"+sComboBoxId+" .combo_box_title").html("");
867		$("#"+sComboBoxId+" .combo_box_title").attr('data-val',"");
868		$("#"+sComboBoxId+" input[type=checkbox]:checked").each(function(){
869			d_root='';
870			d_parent='';
871			d_parent=$(this).attr("data-parent");
872			d_root=$(this).attr("data-root");
873
874			title=$("#"+sComboBoxId+" .combo_box_title").html();
875			value=$("#"+sComboBoxId+" .combo_box_title").attr('data-val');
876
877			if(title!="" && title.charAt(title.length-1)!="(") {
878				$("#"+sComboBoxId+" .combo_box_title").append(", ");
879			}
880			// обычный пункт
881			if(d_parent==undefined && d_root==undefined)
882				{
883				txt = $(this).next("label").html().replace("<br>", " | ");
884				title_value = $("#"+sComboBoxId+" .combo_box_title").attr("data-val");
885				value = $(this).attr('value');
886				dp = $(this).attr('data-parent');
887				value = make_val(title_value, value, dp);
888				//$(".combo_box_title").append(txt).attr("data-val", value);
889				$("#"+sComboBoxId+" .combo_box_title").attr("data-val", value);
890				}
891			// если root
892			if(d_root!=undefined)
893				{
894					// если есть отмеченные потомки
895				if($("#"+sComboBoxId+" input[type=checkbox][data-parent="+d_root+"]:checked").length>0)
896					{
897					txt=$(this).next("label").text()+" (";
898					//$(".combo_box_title").append(txt);
899
900					before_root=d_root;
901					}
902				}
903			// если parent
904			if(d_parent!=undefined)
905				{
906
907					txt=$(this).next("label").text();
908					title_value = $("#"+sComboBoxId+" .combo_box_title").attr("data-val");
909					value = $(this).attr('value');
910					dp = $(this).attr('data-parent');
911					value = make_val(title_value, value, dp);
912					var ind = $("#"+sComboBoxId+" input[type=checkbox][data-parent="+d_parent+"").index(this);
913					if(ind==$("#"+sComboBoxId+" input[type=checkbox][data-parent="+d_parent+"").length-1 && d_parent==before_root){
914						txt+=")";
915					}
916
917					$("#"+sComboBoxId+" .combo_box_title").append(txt).attr("data-val", value);
918				}
919			});
920
921			if($("#"+sComboBoxId+" .combo_box_title").html()=='')
922				$("#"+sComboBoxId+" .combo_box_title").html(src.closest(".combo_box").attr('data-text'));
923
924		/*/
925		var bg = $("#selector").find("input:checked + label[data-bg] ").attr("data-bg");
926		var leng = $("#selector").find("input:checked + label[data-bg] ").length;
927		$("#selector").find("input:checked + label[data-bg] ").each(function(){
928			if ($(this).attr("data-bg") != bg){
929				leng = 0;
930			}
931		});
932		if(bg && leng>0) {
933			$("body").attr("class", bg);
934		} else {
935			$("body").attr("class", "");
936		}
937		/**/
938
939		// bg /
940		return false;
941	}
942
943	function deselectAllCards() {
944		$(".ItemCard").removeClass("selected");
945	}
946	$("body").on('click', ".combo_box input", function(event){
947		return false;
948	});
949
950	$("body").on('click', ".combo_box label", function(){
951		onSelectItemPress($(this));
952		return false;
953	});
954
955	// custom Input
956	$("body").on('click', ".customInput .cross", function(){
957		$(this).parent().find("input").val("");
958		$(this).parent().focusout();
959	});
960
961	// filters
962
963	// name select
964	$("body").on('focusout', "#NameInput", function(){
965		clearTimeout(oTimer);
966		oTimer = setTimeout(function(){
967			updateHash();
968			filterItems();
969		}, nTimerSeconds);
970	});
971	$("body").on('keyup', "#NameInput input", function(){
972		clearTimeout(oTimer);
973		oTimer = setTimeout(function(){
974			updateHash();
975			filterItems();
976		}, nTimerSeconds*3);
977	});
978
979	// tipe combobox
980	$("body").on('click', "#TypeCombobox label", function(){
981		clearTimeout(oTimer);
982		oTimer = setTimeout(function(){
983			updateHash();
984			filterItems();
985		}, nTimerSeconds);
986	});
987	$("body").on('click', "#TypeCombobox .combo_box_title, #TypeCombobox .combo_box_arrow", function(){
988		setConfig("typeOpen", $("#TypeCombobox").attr("data-content-open"));
989	});
990
991	// rarity combobox
992	$("body").on('click', "#RarityCombobox label", function(){
993		clearTimeout(oTimer);
994		oTimer = setTimeout(function(){
995			updateHash();
996			filterItems();
997		}, nTimerSeconds);
998	});
999	$("body").on('click', "#RarityCombobox .combo_box_title, #RarityCombobox .combo_box_arrow", function(){
1000		setConfig("rarityOpen", $("#RarityCombobox").attr("data-content-open"));
1001	});
1002
1003	// source combobox
1004	$("body").on('click', "#SourceCombobox label", function(){
1005		clearTimeout(oTimer);
1006		oTimer = setTimeout(function(){
1007			updateHash();
1008			filterItems();
1009		}, nTimerSeconds);
1010	});
1011	$("body").on('click', "#SourceCombobox .combo_box_title, #SourceCombobox .combo_box_arrow", function(){
1012		setConfig("sourceOpen", $("#SourceCombobox").attr("data-content-open"));
1013	});
1014
1015	// lang select
1016	$("body").on('focusout', "#LangSelect", function(){
1017		clearTimeout(oTimer);
1018		oTimer = setTimeout(function(){
1019			updateHash();
1020			filterItems();
1021		}, nTimerSeconds);
1022	});
1023
1024	// sort select
1025	$("body").on('focusout', "#SortSelect", function(){
1026		clearTimeout(oTimer);
1027		oTimer = setTimeout(function(){
1028			updateHash();
1029			filterItems();
1030		}, nTimerSeconds);
1031	});
1032	// card view select
1033	$("body").on('focusout', "#CardViewSelect", function(){
1034		clearTimeout(oTimer);
1035		oTimer = setTimeout(function(){
1036			updateHash();
1037			filterItems();
1038		}, nTimerSeconds);
1039	});
1040
1041	// show all Items
1042	$("body").on('click', "#showAllItems", function(){
1043		setConfig("infoIsShown", true);
1044    $("#bInfo").addClass("blink");
1045		filterItems();
1046		hideInfoWin();
1047		hideDBG();
1048		return false;
1049	});
1050
1051	//info_textbInfo
1052	$("body").on('click', "#bInfo", function(){
1053		var sInfo = $("#info_text").html();
1054		showDBG();
1055		showInfoWin(sInfo);
1056		return false;
1057	});
1058
1059
1060	//hide Items
1061	$("body").on('click', ".bHideItem", function(){
1062		var sName, sNameRu;
1063
1064		var nSelectedCards = $(".ItemCard.selected").length;
1065		if(nSelectedCards > 0) {
1066			var oButtonLock = $(this);
1067			$(".ItemCard.selected").each(function() {
1068				sName = $(this).closest(".cardContainer").attr("data-name");
1069				sNameRu = $(this).closest(".cardContainer").attr("data-name-ru");
1070
1071				oButtonLock.hide();
1072				// update hidden Items array
1073				aHiddenItems.push({en: sName, ru: sNameRu});
1074			});
1075		} else {
1076			sName = $(this).closest(".cardContainer").attr("data-name");
1077			sNameRu = $(this).closest(".cardContainer").attr("data-name-ru");
1078
1079			$(this).hide();
1080			// update hidden Items array
1081			aHiddenItems.push({en: sName, ru: sNameRu});
1082		}
1083
1084		// show list of hidden Items
1085		createHiddenItemsList();
1086
1087		// show Items without hidden
1088		filterItems({fHidden: true});
1089	})
1090	// unhide Items
1091	$("body").on('click', ".bUnhideItem", function(){
1092		var sName = $(this).attr("data-name")
1093		// update hidden Items array
1094		aHiddenItems.splice(aHiddenItems.map(function(el){return el.en}).indexOf(sName), 1);
1095
1096		// show list of hidden Items
1097		createHiddenItemsList();
1098
1099		// show Items without hidden
1100		filterItems({fHidden: true});
1101
1102		return false;
1103	})
1104	$("body").on("click", ".bReturnUnvisible", function() {
1105		aHiddenItems = [];// show list of hidden Items
1106		createHiddenItemsList();
1107
1108		// show Items without hidden
1109		filterItems({fHidden: true});
1110
1111		return false;
1112	});
1113
1114	// lock Items
1115	$("body").on('click', ".bLockItem", function(){
1116		var sName, sNameRu, sLang;
1117
1118		var nSelectedCards = $(".ItemCard.selected").length;
1119		if(nSelectedCards > 0) {
1120			$(".ItemCard.selected").each(function() {
1121				sName = $(this).closest(".cardContainer").attr("data-name");
1122				sNameRu = $(this).closest(".cardContainer").attr("data-name-ru");
1123				sLang = $(this).closest(".cardContainer").attr("data-lang");
1124				fText = $(this).closest(".cardContainer").hasClass("textView");
1125
1126				aLockedItems[sName] = {
1127					ru: sNameRu,
1128					lang: sLang,
1129          textView: fText
1130					};
1131			});
1132		} else {
1133			sName = $(this).closest(".cardContainer").attr("data-name");
1134			sNameRu = $(this).closest(".cardContainer").attr("data-name-ru");
1135			sLang = $(this).closest(".cardContainer").attr("data-lang");
1136			fText = $(this).closest(".cardContainer").hasClass("textView");
1137
1138			aLockedItems[sName] = {
1139				ru: sNameRu,
1140				lang: sLang,
1141        textView: fText
1142				};
1143		}
1144
1145		// show locked
1146		createLockedItemsArea();
1147		deselectAllCards();
1148	})
1149
1150	// unlock Items
1151	$("body").on('click', ".bUnlockItem", function(){
1152		var sName;
1153
1154		var nSelectedCards = $(".ItemCard.selected").length;
1155		if(nSelectedCards > 0) {
1156			$(".ItemCard.selected").each(function() {
1157				sName = $(this).closest(".cardContainer").attr("data-name");
1158				delete aLockedItems[sName];
1159			});
1160		} else {
1161			sName = $(this).closest(".cardContainer").attr("data-name");
1162			delete aLockedItems[sName];
1163		}
1164
1165		// show locked
1166		createLockedItemsArea();
1167		deselectAllCards();
1168	})
1169	$("body").on('click', "#lockedItemsArea .topHeader", function(){
1170		$(this).next(".content").slideToggle();
1171		$(this).next(".content").next(".bottomHeader").fadeToggle();
1172	});
1173	$("body").on('click', ".bUnlockAll", function(){
1174		aLockedItems = [];
1175		// show locked
1176		createLockedItemsArea();
1177	});
1178
1179	$("body").on('click', "#bPrint", function(){
1180		window.print();
1181
1182		return false;
1183	});
1184
1185	// text size
1186	$("body").on('click', ".textMin", function() {
1187		var f_s=$(this).parent().parent().find(".text").css("font-size");
1188		f_s=f_s.substring(0, f_s.length - 1);
1189		f_s=f_s.substring(0, f_s.length - 1);
1190		//console.log(f_s);
1191
1192		if(f_s>6)
1193		 f_s--;
1194		//console.log(f_s);
1195		var sFontSize = f_s+"px";
1196		var sLineHeight = f_s-1+"px";
1197	    $(this).parent().parent().find(".text").css({"font-size": sFontSize, "line-height": sLineHeight});
1198
1199		$(".ItemCard.selected").each(function() {
1200			$(this).find(".text").css({"font-size": sFontSize, "line-height": sLineHeight});
1201		});
1202
1203		return false;
1204	});
1205	$("body").on('click', ".textMax", function() {
1206		var f_s=$(this).parent().parent().find(".text").css("font-size");
1207		f_s=f_s.substring(0, f_s.length - 1);
1208		f_s=f_s.substring(0, f_s.length - 1);
1209		if(f_s<20)
1210		 f_s++;
1211		//console.log(f_s);
1212		var sFontSize = f_s+"px";
1213		var sLineHeight = f_s-1+"px";
1214	    $(this).parent().parent().find(".text").css({"font-size": sFontSize, "line-height": sLineHeight});
1215
1216		$(".ItemCard.selected").each(function() {
1217			$(this).find(".text").css({"font-size": sFontSize, "line-height": sLineHeight});
1218		});
1219		return false;
1220	});
1221
1222	// card width
1223	$("body").on("click", ".cardWidthMin", function() {
1224		var width;
1225		var nSelectedCards = $(".ItemCard.selected").length;
1226		if(nSelectedCards > 0) {
1227			$(".ItemCard.selected").each(function() {
1228				width = $(this).parent().width();
1229				width = width-20+"px";
1230				$(this).parent().width(width);
1231			});
1232		} else{
1233			width = $(".cardContainer").eq(0).width();
1234			width = width-20+"px";
1235			$('.cardContainer').width(width);
1236			setConfig("cardWidth", width);
1237		}
1238		return false;
1239	});
1240	$("body").on("click", ".cardWidthMax", function() {
1241		var width;
1242		var nSelectedCards = $(".ItemCard.selected").length;
1243		if(nSelectedCards > 0) {
1244			$(".ItemCard.selected").each(function() {
1245				width = $(this).parent().width();
1246				width = (width+20)+"px";
1247				$(this).parent().width(width);
1248			});
1249		} else {
1250			width = $(".cardContainer").eq(0).width();
1251			width = (width+20)+"px";
1252			$('.cardContainer').width(width);
1253			setConfig("cardWidth", width);
1254		}
1255		return false;
1256	});
1257	$("body").on("click", ".cardWidthNorm", function() {
1258		var width = "2.5in";
1259		var nSelectedCards = $(".ItemCard.selected").length;
1260		if(nSelectedCards > 0) {
1261			$(".ItemCard.selected").each(function() {
1262				$(this).parent().width(width);
1263			});
1264		} else {
1265			$('.cardContainer').width(width);
1266			setConfig("cardWidth", width);
1267		}
1268		return false;
1269	});
1270
1271  // autoszie Text in the cards
1272	$("body").on("click", ".cardTestAutoSize", function() {
1273		var nSelectedCards = $(".ItemCard.selected").length;
1274		if(nSelectedCards > 0) {
1275			$(".ItemCard.selected").each(function() {
1276				var f_s=$(this).find(".info").css("font-size");
1277				f_s=f_s.substring(0, f_s.length - 2);
1278				while (f_s > 7 && $(this).find(".info")[0].scrollWidth < $(this).find(".info").innerWidth()) {
1279					f_s-=0.3;
1280
1281					var sFontSize = f_s+"px";
1282					var sLineHeight = f_s-1+"px";
1283					$(this).find(".info").css({"font-size": sFontSize, "line-height": sLineHeight});
1284				}
1285			});
1286		} else {
1287			$(".ItemCard").each(function() {
1288				var f_s=$(this).find(".info").css("font-size");
1289				f_s=f_s.substring(0, f_s.length - 2);
1290				while (f_s > 7 && $(this).find(".info")[0].scrollWidth < $(this).find(".info").innerWidth()) {
1291					 f_s-=0.3;
1292					//console.log(f_s);
1293					var sFontSize = f_s+"px";
1294					var sLineHeight = f_s-1+"px";
1295					$(this).find(".info").css({"font-size": sFontSize, "line-height": sLineHeight});
1296				}
1297			});
1298		}
1299    return false;
1300	});
1301
1302	$(document).keydown(function(event){
1303		// CTRL pressed
1304		if(event.which=="17") {
1305			fCtrlIsPressed = true;
1306		}
1307
1308		// A pressed
1309		if(event.which=="65" && fCtrlIsPressed) {
1310			if($(".ItemCard.selected").length == $(".ItemCard").length) {
1311				// deselect all
1312				$(".ItemCard").removeClass("selected");
1313			} else {
1314				// select all
1315				$(".ItemCard").addClass("selected");
1316			}
1317			//return false;
1318		}
1319	});
1320
1321	$(document).keyup(function(){
1322		fCtrlIsPressed = false;
1323	});
1324
1325	// card select/deselect
1326	$("body").on("click", ".ItemCard", function() {
1327		if(fCtrlIsPressed)
1328			$(this).toggleClass("selected");
1329	});
1330  $("body").on("dblclick", ".ItemCard", function() {
1331		$(this).toggleClass("selected");
1332		clearSelection();
1333		return false;
1334	});
1335	$("body").on("taphold", ".ItemCard", function() {
1336		$(this).toggleClass("selected");
1337	});
1338
1339  // show/hide card info
1340  $("body").on("click", ".sf_text", function(){      
1341    var sInfo = $(this).parent().find(".text").html();
1342    var sName = $(this).parent().find("h1").html();
1343		showDBG();
1344		showInfoWin("<h1>"+sName+"</h1>"+sInfo);
1345		return false;
1346  });
1347
1348  // get random item
1349  $("body").on("click", "#bRandom", function(){   
1350    $("#NameInput input").val("");
1351    getHash({fRandom: true});
1352    return false;
1353  });
1354	
1355	// get random artefakt prop
1356	$("body").on("click", ".randomPropButton", function(){
1357		var oButton = $(this);
1358		var oText = oButton.prev(".randomProp");
1359		var nCount = oText.attr('data-count');
1360		var sKind = oText.attr('data-kind');
1361		var sLang = $("#LangSelect .label").attr("data-selected-key");
1362		var aProps = [], aSource=[];
1363		switch(sKind) {
1364			case "minorBenefit":
1365				aSource = shuffle(aMinorBeneficial[sLang]);		
1366				break;
1367			case "majorBenefit": 
1368				aSource = shuffle(aMajorBeneficial[sLang]);
1369				break;
1370			case "minorDetrim": 
1371				aSource = shuffle(aMinorDetrimenal[sLang]);
1372				break;
1373			case "majorDetrim": 
1374				aSource = shuffle(aMajorDetrimental[sLang]);
1375				break;
1376		}
1377		for(var i=0; i<nCount; i++) {
1378			aProps.push(aSource[i]);
1379		}
1380		oText.html(aProps.join("<br>"));
1381	});
1382	// get random artefakt prop list
1383	$("body").on("click", ".randomProp", function(){
1384		var oText = $(this);
1385		var sKind = oText.attr('data-kind');
1386		var sLang = $("#LangSelect .label").attr("data-selected-key");
1387		var aSource = [];
1388		var sName="";
1389		
1390		switch(sKind) {
1391			case "minorBenefit":
1392				aSource = aMinorBeneficial[sLang];
1393				sName= sLang=="ru"? "Малые положительные свойства" : "Minor Beneficial";				
1394				break;
1395			case "majorBenefit": 
1396				aSource = aMajorBeneficial[sLang];
1397				sName= sLang=="ru"? "Основные положительные свойства" : "Major Beneficial";			
1398				break;
1399			case "minorDetrim": 
1400				aSource = aMinorDetrimenal[sLang];
1401				sName= sLang=="ru"? "Малые отрицательные свйоства" : "Minor Detrimenal";			
1402				break;
1403			case "majorDetrim": 
1404				aSource = aMajorDetrimental[sLang];
1405				sName= sLang=="ru"? "Основные отрицательные свйоства" : "Major Detrimental";			
1406				break;
1407		}
1408		
1409		showDBG();
1410		var sInfo = "<ul>"+aSource.map(function(el){return "<li class='artifProp'>"+el+"</li>";}).join("")+"</ul>";
1411		showInfoWin("<h1>"+sName+"</h1>"+sInfo);
1412	});
1413	
1414	$("body").on("click", ".randomProp a", function(oEvent){
1415		oEvent.stopPropagation();
1416	});
1417	// select artefakt prop
1418	$("body").on("click", ".artifProp", function(){
1419		
1420	});
1421	
1422// url filters
1423	function updateHash() {
1424		// text
1425		var sName = $("#NameInput input").val();
1426
1427		//combobox
1428		var aSources = $("#SourceCombobox .combo_box_title").attr("data-val");
1429			if(aSources) aSources = aSources.split(",").map(function(item){return item.trim()});
1430		var aTypes = $("#TypeCombobox .combo_box_title").attr("data-val");
1431			if(aTypes) aTypes = aTypes.split(",").map(function(item){return item.trim()});
1432		var aRarities = $("#RarityCombobox .combo_box_title").attr("data-val");
1433			if(aRarities) aRarities = aRarities.split(",").map(function(item){return item.trim()});
1434		// select
1435		var sLang = $("#LangSelect .label").attr("data-selected-key");
1436		var sCardView = $("#CardViewSelect .label").attr("data-selected-key");
1437		var sSort = $("#SortSelect .label").attr("data-selected-key");
1438
1439		//#q=Item_name&ls=0&le=9
1440		var aFilters = [];
1441		if(sName && sName.length>0) {
1442			aFilters.push("q="+sName.replace(/\s+/g, "_"));
1443		}
1444		if(aTypes && aTypes.length>0 && $("#TypeCombobox .combo_box_content input").length > aTypes.length) {
1445			aFilters.push("type="+aTypes.join(",").replace(/\s+/g, "_"));
1446		}
1447		if(aSources && aSources.length>0 && $("#SourceCombobox .combo_box_content input").length > aSources.length) {
1448			aFilters.push("source="+aSources.join(",").replace(/\s+/g, "_"));
1449		}
1450		if(aRarities && aRarities.length>0 && $("#RarityCombobox .combo_box_content input").length > aRarities.length) {
1451			aFilters.push("rarity="+aRarities.join(",").replace(/\s+/g, "_"));
1452		}
1453		if(sLang && sLang.length > 0 && sLang != "ru") {
1454			aFilters.push("lang="+sLang.replace(/\s+/g, "_"));
1455		}
1456		if(sCardView && sCardView.length > 0 && sCardView != "card") {
1457			aFilters.push("view="+sCardView.replace(/\s+/g, "_"));
1458		}
1459		if(sSort && sSort.length > 0 && sSort != "rarity_alpha") {
1460			aFilters.push("sort="+sSort.replace(/\s+/g, "_"));
1461		}
1462
1463		if(aFilters.length>0) {
1464			var sHash = aFilters.join("&");
1465			window.location.hash = sHash;
1466		} else {
1467			removeHash();
1468		}
1469	}
1470  function getHash(oParams){
1471    $('html, body').animate({scrollTop:0}, 'fast');
1472
1473    var sHash = window.location.hash.slice(1); // /archive#q=Item_name
1474    sHash = decodeURIComponent(sHash);
1475    if(oParams || sHash && !/[^А-Яа-яЁё\w\d\/&\[\]?|,_=-]/.test(sHash)) {
1476      var sName = (oParams && oParams.fRandom==true)? "" :sHash.match(/\bq=([А-Яа-яЁё\/\w\d_-]+)/);
1477
1478      var sLang = sHash.match(/\blang=([\w]+)/) || ["","ru"];
1479      var sView = sHash.match(/\bview=([\w]+)/) || ["","text"];
1480      var sSort = sHash.match(/\bsort=([\w_]+)/) || ["","rarity_alpha"];
1481
1482      var sRarities = sHash.match(/\brarity=([\w,]+)/);
1483      var sTypes = sHash.match(/\btype=([\w,]+)/);
1484      var sSources = sHash.match(/\bsource=([\w,_]+)/);
1485      
1486      var fRandom = (oParams && oParams.fRandom==true)? true : false;;
1487
1488      if(sName && sName[1]) {
1489      	$("#NameInput input").val(sName[1].replace(/[_]+/g," "));
1490      } else {
1491				$("#NameInput input").val("");
1492			}
1493
1494      if(sLang && sLang[1]) {
1495      	$("#LangSelect .label").attr("data-selected-key", sLang[1]).html($("#LangSelect li[data-key='"+sLang[1]+"']").text().replace(/[_]+/g," "));
1496      } 
1497      if(sView && sView[1]) {
1498      	$("#CardViewSelect .label").attr("data-selected-key", sView[1]).html($("#CardViewSelect li[data-key='"+sView[1]+"']").text().replace(/[_]+/g," "));
1499      }
1500      if(sSort && sSort[1]) {
1501      	$("#SortSelect .label").attr("data-selected-key", sSort[1]).html($("#SortSelect li[data-key='"+sSort[1]+"']").text().replace(/[_]+/g," "));
1502      }
1503
1504      if(sSources && sSources[1]) {
1505      	var aSources = sSources[1].replace("_", " ").split(",");
1506
1507      	$("#SourceCombobox .combo_box_content input[type='checkbox']").each(function(){
1508      		if(aSources.indexOf($(this).val())>-1) {
1509      			$(this).prop('checked', true);
1510      		} else {
1511      			$(this).prop('checked', false);
1512      		}
1513      	});
1514      	$("#SourceCombobox .combo_box_title").attr("data-val", sSources[1].replace("_", " "))
1515      } else {
1516				$("#SourceCombobox .combo_box_content input[type='checkbox']").prop('checked', false);
1517      	$("#SourceCombobox .combo_box_title").attr("data-val", "")
1518			}
1519			
1520      if(sRarities && sRarities[1]) {
1521      	var aRarities = sRarities[1].replace("_", " ").split(",");
1522
1523      	$("#RarityCombobox .combo_box_content input[type='checkbox']").each(function(){
1524      		if(aRarities.indexOf($(this).val())>-1) {
1525      			$(this).prop('checked', true);
1526      		} else {
1527      			$(this).prop('checked', false);
1528      		}
1529      	});
1530      	$("#RarityCombobox .combo_box_title").attr("data-val", sRarities[1].replace("_", " "))
1531      } else {
1532				$("#RarityCombobox .combo_box_content input[type='checkbox']").prop('checked', false);
1533				$("#RarityCombobox .combo_box_title").attr("data-val", "")
1534			}
1535			
1536      if(sTypes && sTypes[1]) {
1537      	var aTypes = sTypes[1].replace("_", " ").split(",");
1538				
1539      	$("#TypeCombobox .combo_box_content input[type='checkbox']").each(function(){
1540      		if(aTypes.indexOf($(this).val())>-1) {
1541      			$(this).prop('checked', true);
1542      		} else {
1543      			$(this).prop('checked', false);
1544      		}
1545      	});
1546      	$("#TypeCombobox .combo_box_title").attr("data-val", sTypes[1].replace("_", " "))
1547      } else {
1548				$("#TypeCombobox .combo_box_content input[type='checkbox']").prop('checked', false);
1549				$("#TypeCombobox .combo_box_title").attr("data-val", "")
1550			}
1551
1552      // if(sLang && sLang[1]) {
1553      // 	$("#LangSelect .label").attr("data-selected-key", sLang[1]).html($("#LangSelect li[data-key='"+sLang[1]+"']").html().replace("<br>", " | "));
1554      // }
1555    } else {
1556      removeHash();
1557      //hideClerFilter();
1558    }
1559    //$("body").css("border-top", "1px solid red");
1560    filterItems({fRandom: fRandom});
1561  }
1562
1563  function removeHash() {
1564    history.pushState("", document.title, window.location.pathname + window.location.search);
1565    return false;
1566  }
1567  //window.onhashchange = getHash;
1568
1569	
1570	
1571	
1572	
1573	$("body").on("click", "#bDownload", function() {
1574		downloadDB();
1575	});
1576	$("body").on("click", "#bUpload", function() {
1577		uploadDB();
1578	});
1579	$("body").on("change", "#fileUploader", function(oEvent) {
1580		fileSelected (oEvent);
1581	});
1582	
1583	
1584	function downloadDB() {
1585
1586		var oDB = {};
1587		oDB.sourceList = oSources;
1588		oDB.typesList = oTypes;
1589		oDB.rarityList = oRarity;
1590		oDB.addList = oItemsAddInfo;
1591		oDB.minorBenList = aMinorBeneficial;
1592		oDB.majorBenList = aMajorBeneficial;
1593		oDB.minorDetList = aMinorDetrimenal;
1594		oDB.majorBenList = aMajorDetrimental;
1595		oDB.itemsList = allItems;
1596		
1597		var sData = JSON.stringify(oDB, null, 2);
1598		var filename = "DnD5e_equipment_BD";
1599		var blob = new Blob([sData], {type: "text/plain;charset=utf-8"});
1600		saveAs(blob, filename+".dtn");
1601	}
1602	function uploadDB() {
1603		document.getElementById('fileUploader').click();
1604	}
1605	function fileSelected (oEvent){
1606		handleLocalBDSelect(oEvent);
1607	}
1608	
1609	function  handleLocalBDSelect(evt) {
1610		var files = evt.target.files; // FileList object
1611
1612		var reader = new FileReader();
1613		reader.onload = (function(theFile) {
1614			return function(e) {
1615				var sText = e.target.result;
1616				parceLocalFile(sText);
1617			}.bind(this);
1618		}.bind(this))(files[0]);
1619
1620		// Read in the image file as a data URL.
1621		reader.readAsText(files[0]);
1622
1623	}
1624	function parceLocalFile(sText) {
1625		var oDB = JSON.parse(sText);
1626		
1627		oSources = oDB.sourceList;
1628		oTypes = oDB.typesList;
1629		oRarity = oDB.rarityList;
1630		oItemsAddInfo = oDB.addList;
1631		aMinorBeneficial = oDB.minorBenList;
1632		aMajorBeneficial = oDB.majorBenList;
1633		aMinorDetrimenal = oDB.minorDetList;
1634		aMajorDetrimental = oDB.majorBenList;
1635		allItems = oDB.itemsList;
1636		
1637		getHash();
1638	}
1639
1640	
1641	
1642	
1643window.onhashchange = getHash;
1644// /url filters
1645
1646
1647	$.when(createSidebar()).done(
1648		function(){
1649      //$("body").css("border-top", "1px solid blue");
1650			if(window.location.hash.length>0 || getConfig("infoIsShown")==true){
1651				getHash();
1652			}
1653			$("#showAllItems").slideDown();
1654			// if(getViewPortSize("width") > 600){
1655				// if(getConfig("infoIsShown")==true)
1656					// getHash();
1657					// filterItems();
1658			// } else{
1659        // setTimeout(getHash, 1000);
1660        // getHash();
1661      // }
1662		}
1663	);
1664};

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.