PageSourceSearch

https://s17.8888.bg/js/bg/app/compat/dist/compat.iife.js?v=1790237098

js 8888.bg collected 2026-09-24 10:39:54 UTC 113,738 bytes, 3,199 lines download raw bytes

1/* compat.iife.js — АВТОГЕНЕРИРАН от app/compat/build.js. НЕ РЕДАКТИРАЙ тук.
2 * Източници (в ред на конкатенация):
3 *   vendor/01-core.js
4 *   vendor/02-event-dispatcher.js
5 *   vendor/03-base-manager.js
6 *   vendor/04-base-element.js
7 *   vendor/05-ui-manager.js
8 *   vendor/06-dom-target.js
9 *   vendor/07-dom-targets.js
10 *   vendor/08-ui-element-class.js
11 *   vendor/09-timer.js
12 *   vendor/10-helpers.js
13 *   vendor/11-network-ajax.js
14 *   vendor/12-core-currency.js
15 *   vendor/13-uaparser.js
16 *   vendor/14-cookie.js
17 *   vendor/15-local-storage.js
18 *   vendor/16-dragger.js
19 *   shim.js
20 *   hydrator.js
21 */
22
23/* ==================== vendor/01-core.js ==================== */
24;
25/* File: Compat vendor - bg.ecard core (extendClass slice) */
26/* ДОСЛОВНО копие от: bg.ecard\bg.ecard.js (root) — namespace + utils.extendClass (редове 2-3, 108-137).
27 * НЕ РЕДАКТИРАЙ. Тук е взет само extendClass — той е всичко, което manager веригата (BaseManager/
28 * UIManager) ползва. Останалото от root core (includeJS, parseCurrency, parseCurrencyToNumber, isInt,
29 * plural, Number.prototype.formatCurrency) е loose-глобален контракт на КАМПАНИИТЕ и идва по-късно,
30 * заедно с vendored UIElementClass (там се решават и P2 колизиите с framework глобалите). */
31var bg = bg || new Object();
32bg.ecard = bg.ecard || new Object();
33
34bg.ecard.utils = bg.ecard.utils || new Object();
35
36bg.ecard.utils.extendClass = function (source, target, skipInitClass) {
37	//console.log('bg.ecard.classExted()', source.prototype.params.type, target.params.type);
38	if (bg.ecard.app) {
39		//bg.ecard.app.log('bg.ecard.extendClass()', target.params.type, source.prototype.params.type);
40	}
41
42	for (var i in source.prototype) {
43		if (!target[i]) {
44			target[i] = source.prototype[i];
45		}
46	}
47
48	if (!target.params.extendedFrom) {
49		target.params.extendedFrom = new Array(source.prototype.params.type);
50	} else {
51		target.params.extendedFrom.push(source.prototype.params.type);
52	}
53
54	if (!skipInitClass) {
55		if (target.initClass) {
56			target.initClass();
57		}
58		if (source.prototype.params.initClassFunc) {
59			target[source.prototype.params.initClassFunc]();
60		}
61	}
62
63};
64
65
66/* ==================== vendor/02-event-dispatcher.js ==================== */
67;
68/* File: Compat vendor - bg.ecard.EventDispatcher (per-instance dispatcher class) */
69/* ДОСЛОВНО копие от: bg.ecard\main\bg.ecard.EventDispatcher.js. НЕ РЕДАКТИРАЙ.
70 * Това е КЛАСЪТ за per-instance dispatcher-ите (this.events = new bg.ecard.EventDispatcher(this)
71 * в BaseManager/BaseElement/UIElementClass) — винаги е бил ИЗОЛИРАН (собствен this.events map),
72 * различен от споделения app.events bus (него го дава shim.js адаптерът). */
73/*# bg.ecard.EventDispatcher   */
74bg.ecard.EventDispatcher = function (parent, params) {
75
76	if (params) { this.params = params; } else { this.params = {}; }
77	if (parent) {
78		this.parent = parent;
79		this.params.parent = this.parent;
80		this.params.id = parent.params.type + '-' + parent.params.id;
81	}
82	this.params.type = 'bg.ecard.EventDispatcher';
83
84	this.params.triggerAsync = false;
85
86	this.events = {};
87	this.disabledEvents = [];
88
89	window.logEvents = function (){
90		console.log(this.events);
91
92		let total = 0
93		for (let eventType in this.events) {
94			total += this.events[eventType].length;
95		}
96
97		// console.log("TOTAL", total)
98
99	}.bind(this)
100
101}
102
103bg.ecard.EventDispatcher.prototype.bind = function (eventType, caller, action, execOnce) {
104	if (caller.params) {
105
106	} else {
107
108	}
109
110	if (!this.events[eventType]) {
111		this.events[eventType] = [];
112	}
113
114	this.events[eventType].push(new bg.ecard.EventDispatcher.Event(this, { 'eventType': eventType, 'caller': caller, 'action': action, 'execOnce': execOnce }));
115
116}
117
118bg.ecard.EventDispatcher.prototype.unbind = function (eventType, caller, action) {
119
120	if (this.events[eventType]) {
121		for (var i = 0; i < this.events[eventType].length; i++) {
122			var eventi = this.events[eventType][i];
123			if ((eventi.params.caller === caller) && (eventi.params.action === action)) {
124				this.events[eventType].splice(i, 1);
125			}
126		}
127
128		if (this.events[eventType].length == 0) {
129			// console.log(eventType)
130			delete this.events[eventType];
131		}
132	} else {
133		//console.warn("MISSING EVENT:::", eventType)
134	}
135
136}
137
138bg.ecard.EventDispatcher.prototype.unbindAll = function (caller){
139	// console.log("unbindAll", this.events)
140	for (let eventType in this.events) {
141
142		for (var i = this.events[eventType].length- 1; i > -1 ; i--) {
143			var eventi = this.events[eventType][i];
144			if ((eventi.params.caller === caller)) {
145				this.events[eventType].splice(i, 1);
146			}
147		}
148	}
149}
150
151bg.ecard.EventDispatcher.prototype.trigger = function (eventType, data, data2) {
152	if (eventType.indexOf('timer.') < 0)
153
154		 window.dispatchEvent(new CustomEvent("bridge:event", { detail: { event:eventType,  data: data, data2:data2 } }))
155		if (this.events[eventType]) {
156			if (this.disabledEvents[eventType]) {
157			} else {
158				//if (this.events[eventType] && this.events[eventType].length) {
159				for (var i = 0; i < this.events[eventType].length; i++) {
160					this.events[eventType][i].trigger(data, data2);
161
162					if (!this.events[eventType]) break;
163				}
164				//}
165			}
166		}
167
168}
169
170bg.ecard.EventDispatcher.prototype.disable = function (eventType) {
171
172	this.disabledEvents[eventType] = true;
173
174}
175
176bg.ecard.EventDispatcher.prototype.enable = function (eventType) {
177
178	this.disabledEvents[eventType] = false;
179	delete this.disabledEvents[eventType];
180
181}
182
183bg.ecard.EventDispatcher.Event = function (parent, params) {
184
185	this.parent = parent;
186	this.params = params;
187	this.params.parent = this.parent;
188
189	this.params.type = 'bg.ecard.EventDispatcher.Event';
190	if (this.params.caller.params) {
191		this.params.id = this.params.caller.params.id + '---' + this.params.action;
192	} else {
193		this.params.id = 'outOfFramework' + '---' + this.params.action;
194	}
195
196	if (bg.ecard.app.params.debug) {
197
198	} else {
199
200	}
201
202}
203
204bg.ecard.EventDispatcher.Event.prototype.trigger = function (data, data2) {
205
206	if (typeof (this.params.caller[this.params.action]) === 'function') {
207		if (this.parent.params.triggerAsync) {
208			var _that = this;
209			setTimeout(function () {
210				_that.params.caller[_that.params.action](data, data2, { caller: _that.params.caller, eventParams: { action: _that.params.action, name: _that.params.eventType } });
211			}, 0);
212		} else {
213			this.params.caller[this.params.action](data, data2, { caller: this.params.caller, eventParams: { action: this.params.action, name: this.params.eventType } });
214		}
215		if (this.params.execOnce) {
216			this.parent.unbind(this.params.eventType, this.params.caller, this.params.action);
217		}
218	} else {
219		//    bg.ecard.app.die({errorId: 'Event triger target action missing', elementName: this.params.caller.params.type + ' - action: ' + this.params.action});
220		console.error({ errorId: 'Event triger target action missing', elementName: this.params.caller.params.type + ' - action: ' + this.params.action });
221	}
222
223}
224
225
226/* ==================== vendor/03-base-manager.js ==================== */
227;
228/* File: Compat vendor - bg.ecard.BaseManager */
229/* ДОСЛОВНО копие от: bg.ecard\main\bg.ecard.BaseManager.js. НЕ РЕДАКТИРАЙ. */
230/*#  bg.ecard.BaseManager */
231bg.ecard.BaseManager = function() {
232
233}
234
235bg.ecard.BaseManager.prototype.params = {
236  type: 'bg.ecard.BaseManager',
237  initClassFunc: 'initClassBaseManager'
238}
239
240bg.ecard.BaseManager.prototype.initClassBaseManager = function() {
241
242  if (!this.elements) {
243    this.elements = [];
244  }
245//  this.elements = {};
246  this.active = null;
247
248  this.events = new bg.ecard.EventDispatcher(this);
249}
250
251bg.ecard.BaseManager.prototype.setActive = function(elementObj) {
252
253  this.active = elementObj;
254}
255
256
257/* ==================== vendor/04-base-element.js ==================== */
258;
259/* File: Compat vendor - bg.ecard.BaseElement */
260/* ДОСЛОВНО копие от: bg.ecard\main\bg.ecard.BaseElement.js. НЕ РЕДАКТИРАЙ.
261 * Базов клас за UIElementClass (кампанийните елементи). За самия хидратор не е задължителен,
262 * но е част от базовата верига и е нужен, щом хидраторът инстанцира кампаниен клас. */
263/*#  bg.ecard.BaseElement */
264bg.ecard.BaseElement = function(parent, params) {}
265
266bg.ecard.BaseElement.prototype.params = {
267	id: 'BaseElement',
268	type: 'bg.ecard.BaseElement',
269	initClassFunc: 'initClassBaseElement'
270}
271
272bg.ecard.BaseElement.prototype.initClassBaseElement = function() {
273
274	if (!this.state) {
275		this.state = {};
276	}
277
278	if (!this.events) {
279		this.events = new bg.ecard.EventDispatcher(this);
280	}
281}
282
283bg.ecard.BaseElement.prototype.setState = function(stateId) {
284
285	this.state[stateId] = true;
286
287	if (this.holder) {
288		for (var i in this.holder) {
289			this.holder[i].setState(stateId);
290		}
291	}
292}
293
294bg.ecard.BaseElement.prototype.removeState = function(stateId) {
295
296	delete this.state[stateId];
297	if (this.holder) {
298		for (var i in this.holder) {
299			this.holder[i].removeState(stateId);
300		}
301	}
302}
303
304bg.ecard.BaseElement.prototype.setData = function(dataObj) {
305
306//	this.state[stateId] = true;
307
308	if (this.holder) {
309		for (var i in this.holder) {
310			this.holder[i].setData(dataObj);
311		}
312	}
313}
314
315
316/* ==================== vendor/05-ui-manager.js ==================== */
317;
318/* File: Compat vendor - bg.ecard.UIManager */
319/* ДОСЛОВНО копие от: bg.ecard\main\bg.ecard.UIManager.js. НЕ РЕДАКТИРАЙ.
320 * updateLabels реферира bg.ecard.UIElementLabel (немигриран) — но хидраторът НЕ вика updateLabels,
321 * така че липсата му не пречи. */
322/*#  bg.ecard.UIManager */
323bg.ecard.managersList = {};
324bg.ecard.UIManager = function (parent) {
325
326	this.params = {
327		type: 'bg.ecard.UIManager',
328		id: 'ui-' + parent.params.id,
329		parent: parent,
330	};
331
332	this.labels = {};
333
334	this.uiElements = {};//TODO CHECK
335	// this.managersList = {};
336	bg.ecard.utils.extendClass(bg.ecard.BaseManager, this);
337
338	//	console.log('new bg.ecard.UIManager');
339}
340
341bg.ecard.UIManager.prototype.addElement = function (elementToAdd, index) {
342	this.uiElements[index] = elementToAdd;
343	// console.log(elementToAdd, index)
344	if (elementToAdd.events)
345		elementToAdd.events.trigger('underManagement', this);
346	return elementToAdd;
347}
348
349bg.ecard.UIManager.prototype.addManager = function (elementToAdd, id) {
350	bg.ecard.managersList[id] = elementToAdd;
351	// bg.ecard.app.interface.ui
352	return elementToAdd;
353}
354
355bg.ecard.UIManager.prototype.updateLabels = function (labelsObj) {
356
357	for (var i in labelsObj) {
358		//		var labelInfo = labelsObj[i];
359		if (this.labels[i]) {
360			//update LABEL
361		} else {
362			//create LABEL
363			bg.ecard.app.interface.ui.addElement(new bg.ecard.UIElementLabel(this, { id: i, value: labelsObj[i] }));
364		}
365	}
366}
367
368
369/* ==================== vendor/06-dom-target.js ==================== */
370;
371/* File: Compat vendor - bg.ecard.DomTarget */
372/* ДОСЛОВНО копие от: bg.ecard\main\bg.ecard.DomTarget.js. НЕ РЕДАКТИРАЙ.
373 * Wrapper-ът, който хидраторът подава на кампанийните класове като { domEl: <DomTarget> }.
374 * .html() currency/secToMin пътищата реферират Number.prototype.formatCurrency / app.time —
375 * НЕ се задействат при хидратация (хидраторът чете само .target/.getAttribute). */
376
377/*# bg.ecard.DomTarget  */
378bg.ecard.DomTarget = function( selector, createClone, is2scr, parentDomObj, prepend ) {
379	this.params = {	type: 'bg.ecard.DomTarget' };
380
381	if (!selector) {
382		if (bg.ecard.app.error) {
383			bg.ecard.app.error('bg.ecard.DomTarget created with no selector');
384		} else {
385			console.error('bg.ecard.DomTarget created with no selector');
386		}
387		return;
388	}
389
390	//  console.log( this, selector );
391
392	if (bg.ecard.app && bg.ecard.app.params.debug && bg.ecard.app.console) {
393
394	} else {
395
396	}
397
398	if ( typeof(selector) === 'string' ) {
399		this.params.id = selector;
400		this.params.selector = selector;
401	} else {
402		this.target = selector;
403		this.params.selector = selector;
404		this.params.id = selector.tagName;
405	}
406
407	this.state = {};
408
409	this.attachedState = new Array();
410
411	this.init( createClone, is2scr, parentDomObj, prepend );
412}
413
414bg.ecard.DomTarget.prototype.init = function(createClone, is2scr, parentDomObj, prepend) {
415
416	//  console.log('bg.ecard.DomTarget.prototype.init', prepend);
417
418	if (!is2scr) {
419		var docToSearch = document;
420	} else {
421		if (app.secondScreen.secondScreen) {
422			var docToSearch = app.secondScreen.secondScreen.document;
423		}
424	}
425
426	if (parentDomObj){
427		//console.log( 'parentDomObj: ', parentDomObj);
428		docToSearch = parentDomObj;
429	}
430
431	if (createClone) { // clone DOM element from selector
432
433		var cloneSource = docToSearch.querySelector( this.params.selector );
434		//		console.log(docToSearch, this.params.selector, cloneSource);
435		if (!cloneSource) {
436			//app.die({errorId:'domTarget - clone source element missing', elementName:''+this.params.selector});
437			return false;
438		}
439		if (prepend === true) {
440			this.target = cloneSource.parentNode.insertBefore( cloneSource.cloneNode(true), cloneSource.parentNode.firstChild.nextSibling );
441		} else {
442			this.target = cloneSource.parentNode.appendChild( cloneSource.cloneNode(true) );
443		}
444		this.target.prevDisplayState = cloneSource.prevDisplayState;
445
446	} else { // just search DOM
447
448		if (!this.target) this.target = docToSearch.querySelector( this.params.selector );
449
450	}
451
452	if (!this.target) {
453
454		return false;
455		//		app.die({errorId: 'domTarget created for non-existant dom element', elementName: this.params.selector});
456
457	}
458
459	this.style = this.target.style;
460	this.targetDomTag = this.target.tagName;
461	//  this.targetDataType = this.target.dataset.type;
462	this.targetDataType = this.target.getAttribute('data-type');
463
464	//	console.log( this.target );
465}
466
467bg.ecard.DomTarget.prototype.button = function(domEl) {
468
469	var actionValue = domEl.innerHTML;
470	if (domEl.dataset && domEl.dataset['action']) {
471		var action = domEl.dataset['action'];
472	} else {
473		var action = domEl.innerHTML.toLowerCase();
474	}
475
476	if (this.target.tagName === 'INPUT') {
477
478		if (action === 'back' || action === '&lt;'|| action === '&#8592;' || action === '←') { // backspace
479
480			var currValue = this.target.value;
481			var currPos = this.target.selectionStart;
482			if (currPos === 0) {
483				app.active.input.focus();
484				return;
485			}
486			this.target.value = currValue.slice(0, currPos - 1) + currValue.slice(currPos, currValue.length);
487			this.target.setSelectionRange(currPos - 1, currPos - 1);
488			app.active.input.focus();
489
490		} else if ( (action === 'ent') || (action === 'ok') ) { // enter
491
492			if ( this.target.dataset.action && this.target.dataset.target ) {
493
494				if (this.target.dataset.target === 'section') {
495					app.active.section.events.trigger( this.target.dataset.action, this.target );
496					return true;
497				}	else if (this.target.dataset.target === 'element') {
498					//					var targetEl = app.getElement( this.target.dataset.eltype, this.target.dataset.elid );
499					//					console.log( 'targetEl:', targetEl );
500					//					if (targetEl) {
501					//						targetEl.events.trigger(domEl.dataset.action, domEl);
502					//					}
503				}
504			} else {
505				//console.log( 'ENT', domEl );
506				app.input.clearSelection();
507			}
508
509		} else if ( action === 'moveL' ) {
510
511			this.target.setSelectionRange(this.target.selectionStart-1, this.target.selectionStart-1);
512			app.active.input.focus();
513
514		} else if ( action === 'moveR' ) {
515
516			this.target.setSelectionRange(this.target.selectionStart+1, this.target.selectionStart+1);
517			app.active.input.focus();
518
519		} else { // fill button value in input
520
521			var shouldAdd = true;
522			if (this.target.dataset.maxlength) { // input el has data-maxlength set
523				if ( parseInt(this.target.dataset.maxlength) <= this.target.value.length ) {
524					shouldAdd = false;
525				}
526			}
527
528			if (shouldAdd) {
529				var currValue = this.target.value;
530				var currPos = this.target.selectionStart;
531				this.target.value = currValue.slice(0, currPos) + actionValue + currValue.slice(currPos, currValue.length);
532				this.target.setSelectionRange(currPos+1, currPos+1);
533			}
534			app.active.input.focus();
535
536		}
537
538	}
539
540}
541
542bg.ecard.DomTarget.prototype.html = function( htmlStr ) {
543//
544
545	if (!this.target) {
546		return;
547	}
548
549	//	if (!htmlStr) {
550	//		return this.target.innerHTML;
551	//	}
552
553	if (this.targetDataType == 'currency') {
554		htmlStr = parseFloat(htmlStr).formatCurrency(0,'.','&nbsp;')
555	} else if (this.targetDataType == 'secToMin') {
556		htmlStr = app.time.secondsToTime(parseInt(htmlStr));
557	}
558
559	if (this.targetDomTag === 'INPUT') {
560		this.target.value = htmlStr;
561	} else {
562		this.target.innerHTML = htmlStr;
563	}
564
565}
566
567bg.ecard.DomTarget.prototype.getValues = function() {
568	if (this.target.tagName !== 'FORM') return;
569
570	var inputEls = this.target.querySelectorAll('input');
571	var retObj = {};
572
573	for (var i=0; i<inputEls.length; i++) {
574		retObj[inputEls[i].name] = inputEls[i].value;
575	}
576
577	return retObj;
578}
579
580bg.ecard.DomTarget.prototype.getValue = function() {
581	//	if (this.target.tagName !== 'INPUT') return;
582
583	if (this.target.tagName === 'INPUT') {
584		return this.target.value;
585	} else {
586		return this.target.textContent;
587	}
588}
589
590bg.ecard.DomTarget.prototype.setValue = function( valueToSet ) {
591	if (this.target.tagName !== 'INPUT') return;
592
593	this.target.value = valueToSet;
594}
595
596bg.ecard.DomTarget.prototype.serialize = function() {
597	if (this.target.nodeName !== 'FORM') return;
598
599	var inputEls = this.target.querySelectorAll('input, select');
600	var retObj = [];
601
602	for (var i=0; i<inputEls.length; i++) {
603		//    console.log(inputEls[i], inputEls[i].value);
604		retObj.push( inputEls[i].name + '=' + encodeURIComponent(inputEls[i].value) );
605	}
606
607	return retObj.join('&');
608}
609
610bg.ecard.DomTarget.prototype.select = function() {
611
612	this.addClass('active');
613	//	this.target.setAttribute('selected','selected')
614
615}
616
617bg.ecard.DomTarget.prototype.deselect = function() {
618
619	this.removeClass('active');
620	//	this.target.setAttribute('selected','selected')
621
622}
623
624bg.ecard.DomTarget.prototype.clear = function() {
625
626	if (!this.target) {
627		return;
628	}
629
630	if (this.target.nodeName !== 'FORM') return;
631
632	var inputEls = this.target.querySelectorAll('input');
633
634	for (var i=0; i<inputEls.length; i++) {
635		inputEls[i].value = '';
636	}
637
638}
639
640bg.ecard.DomTarget.prototype.show = function() {
641
642	if (!this.target) {
643		return;
644	}
645
646	this.target.style.visibility = 'visible';
647
648	if (this.target.prevDisplayState && this.target.prevDisplayState != 'none') {
649		this.target.style.display = this.target.prevDisplayState;
650	} else {
651		this.target.style.display = 'block';
652	}
653}
654
655bg.ecard.DomTarget.prototype.hide = function() {
656
657	// console.log(this);
658	if (this.target) {
659		// console.log(window.getComputedStyle( this.target ));
660		this.target.prevDisplayState = window.getComputedStyle( this.target ).display;
661
662		this.target.style.visibility = 'hidden';
663		this.target.style.display = 'none';
664	}
665}
666
667bg.ecard.DomTarget.prototype.focus = function() {
668	this.target.focus();
669}
670
671bg.ecard.DomTarget.prototype.blur = function() {
672	this.target.blur();
673}
674
675bg.ecard.DomTarget.prototype.find = function(selector, returnDomTarget) {
676
677	if (!this.target) {
678		return;
679	}
680
681	if (returnDomTarget) {
682		return new bg.ecard.DomTarget( this.target.querySelector(selector) );
683	} else {
684		return this.target.querySelector(selector);
685	}
686}
687
688bg.ecard.DomTarget.prototype.findAll = function(selector) {
689	if (this.target) {
690		return this.target.querySelectorAll(selector);
691	}
692}
693
694bg.ecard.DomTarget.prototype.removeClass = function(className) {
695	if (this.target) {
696		if (this.target.classList.contains(className) ) {
697			this.target.classList.remove( className );
698		}
699	}
700}
701
702bg.ecard.DomTarget.prototype.addClass = function(className) {
703	if (this.target) {
704		this.target.classList.add( className );
705	}
706}
707
708bg.ecard.DomTarget.prototype.setData = function(dataObj) {
709	if (this.target) {
710		for (var i in dataObj) {
711			//this.target.dataset[i] = dataObj[i];
712			this.target.setAttribute('data-'+i.replace(/([A-Z])/g, "-$1").toLowerCase(), dataObj[i]);
713		}
714	}
715}
716
717bg.ecard.DomTarget.prototype.getData = function(dataId) {
718	if (this.target) {
719		return this.target.getAttribute('data-'+dataId);
720	}
721}
722
723bg.ecard.DomTarget.prototype.removeData = function(dataAtributeName) {
724	if (this.target) {
725		this.target.removeAttribute('data-'+dataAtributeName.replace(/([A-Z])/g, "-$1").toLowerCase());
726	}
727
728}
729
730bg.ecard.DomTarget.prototype.setAttribute = function(attributeName, attributeValue) {
731
732	this.target.setAttribute(attributeName.replace(/([A-Z])/g, "-$1").toLowerCase(), attributeValue);
733}
734
735bg.ecard.DomTarget.prototype.removeAttribute = function(attributeName) {
736
737	this.target.removeAttribute(attributeName.replace(/([A-Z])/g, "-$1").toLowerCase());
738}
739
740bg.ecard.DomTarget.prototype.getAttribute = function(attributeName) {
741	if (this.target) {
742		return this.target.getAttribute(attributeName);
743	}
744}
745
746bg.ecard.DomTarget.prototype.remove = function() {
747	this.target.parentNode.removeChild(this.target);
748}
749
750bg.ecard.DomTarget.prototype.setState = function(stateId) {
751
752	this.state[stateId] = true;
753
754	this.addClass('app-state-'+stateId);
755	if (this.attachedState) {
756		for (var i = 0; i < this.attachedState.length; i++) {
757			this.attachedState[i].addClass('app-state-'+stateId);
758		}
759	}
760}
761
762bg.ecard.DomTarget.prototype.removeState = function(stateId) {
763
764	delete this.state[stateId];
765
766	this.removeClass('app-state-'+stateId);
767	if (this.attachedState) {
768		for (var i = 0; i < this.attachedState.length; i++) {
769			this.attachedState[i].removeClass('app-state-'+stateId);
770		}
771	}
772
773}
774
775bg.ecard.DomTarget.prototype.removeStates = function( partStateId ) {
776
777	if (partStateId) {
778		for (var i=0; i < this.target.classList.length; i++) {
779			if (this.target.classList[i].indexOf(partStateId) >= 0) {
780				this.removeClass(this.target.classList[i]);
781				i--;
782			}
783		}
784
785		for (var i in this.state) {
786			if (i.indexOf(partStateId) >= 0) {
787				delete this.state[i];
788			}
789		}
790
791	} else { // remove All states
792
793		for (var i in this.state) {
794			this.removeClass( 'app-state-' + i );
795			delete this.state[i];
796		}
797
798	}
799
800}
801
802bg.ecard.DomTarget.prototype.appendStringAsNodes = function(html) {
803	//	return;
804	var element = this.target;
805	var frag = document.createDocumentFragment(),
806			tmp = document.createElement('body'), child;
807	tmp.innerHTML = html;
808	// Append elements in a loop to a DocumentFragment, so that the browser does
809	// not re-render the document for each node
810	while (child = tmp.firstChild) {
811		frag.appendChild(child);
812	}
813	element.appendChild(frag); // Now, append all elements at once
814	frag = tmp = null;
815	//	document.getElementById('s').pr
816}
817
818bg.ecard.DomTarget.prototype.prependStringAsNodes = function(html) {
819	//	return;
820	var element = this.target;
821	var frag = document.createDocumentFragment(),
822			tmp = document.createElement('body'), child;
823	tmp.innerHTML = html;
824	// Append elements in a loop to a DocumentFragment, so that the browser does
825	// not re-render the document for each node
826	while (child = tmp.firstChild) {
827		frag.appendChild(child);
828	}
829	element.insertBefore(frag, element.firstChild); // Now, append all elements at once
830	frag = tmp = null;
831	//	document.getElementById('s').pr
832}
833
834bg.ecard.DomTarget.prototype.css = function(styleParam, styleValue) {
835
836	if ( (parseInt(styleValue) == styleValue) || (parseFloat(styleValue) == styleValue) ) {
837		styleValue += 'px';
838	}
839	this.target.style[styleParam] = styleValue;
840
841}
842
843bg.ecard.DomTarget.prototype.appendChild = function(domObj) {
844
845	if (this.target) {
846		this.target.appendChild(domObj);
847	}
848}
849
850//bg.ecard.utils.registerJS('bg.ecard.DomTarget.js');
851
852
853/* ==================== vendor/07-dom-targets.js ==================== */
854;
855/* File: Compat vendor - bg.ecard.DomTargets */
856/* ДОСЛОВНО копие от: bg.ecard\main\bg.ecard.DomTargets.js. НЕ РЕДАКТИРАЙ.
857 * Хидраторът го ползва за сканиране: new bg.ecard.DomTargets({parentEl, query}) → .targets / .targetDOMs. */
858/*# bg.ecard.DomTargets   */
859bg.ecard.DomTargets = function( params ) {
860
861	if (params) {
862		this.params = params;
863		if (params.parent) this.parent = params.parent;
864	} else {
865		this.params = {};
866	}
867
868	this.params.type = 'bg.ecard.DomTargets';
869	this.params.id = this.params.query;
870
871	/*
872	if ( typeof(selector) === 'string' ) {
873		this.params.id = selector;
874		this.params.selector = selector;
875	} else {
876		this.target = selector;
877		this.params.selector = selector;
878	}
879	*/
880
881	this.init();
882
883}
884
885bg.ecard.DomTargets.prototype.init = function() {
886
887	if (this.params.parentEl.target) {
888		this.params.parentEl = this.params.parentEl.target;
889	}
890
891	this.targets = this.params.parentEl.querySelectorAll( this.params.query );
892	this.targetDOMs = [];
893
894	for (var i=0; i <this.targets.length; i++) {
895		this.targetDOMs.push( new bg.ecard.DomTarget(this.targets[i]) );
896	}
897
898}
899
900bg.ecard.DomTargets.prototype.button = function(domEl) {
901
902}
903
904bg.ecard.DomTargets.prototype.html = function( htmlStr ) {
905
906	//ANTON PATCH
907	if ( !this.targetDOMs ) {
908		return;
909	}
910
911	//console.log('!!!!!!!!!');
912
913	for (var i=0; i<this.targetDOMs.length; i++) {
914		this.targetDOMs[i].html( htmlStr );
915	}
916
917}
918
919bg.ecard.DomTargets.prototype.getValues = function() {
920
921}
922
923bg.ecard.DomTargets.prototype.getValue = function() {
924
925}
926
927bg.ecard.DomTargets.prototype.serialize = function() {
928
929}
930
931bg.ecard.DomTargets.prototype.select = function() {
932
933	for (var i=0; i<this.targetDOMs.length; i++) {
934		this.targetDOMs[i].select();
935	}
936}
937
938bg.ecard.DomTargets.prototype.deselect = function() {
939
940	for (var i=0; i<this.targetDOMs.length; i++) {
941		this.targetDOMs[i].deselect();
942	}
943}
944
945bg.ecard.DomTargets.prototype.setState = function(stateId) {
946
947	for (var i=0; i<this.targetDOMs.length; i++) {
948		this.targetDOMs[i].setState(stateId);
949	}
950
951}
952
953bg.ecard.DomTargets.prototype.removeState = function(stateId) {
954
955	for (var i=0; i<this.targetDOMs.length; i++) {
956		this.targetDOMs[i].removeState(stateId);
957	}
958
959}
960
961bg.ecard.DomTargets.prototype.setValue = function( newValue ) {
962
963	for (var i=0; i<this.targetDOMs.length; i++) {
964		this.targetDOMs[i].setValue(newValue);
965	}
966}
967
968bg.ecard.DomTargets.prototype.show = function() {
969
970}
971
972bg.ecard.DomTargets.prototype.hide = function() {
973
974}
975
976bg.ecard.DomTargets.prototype.focus = function() {
977
978}
979
980bg.ecard.DomTargets.prototype.blur = function() {
981
982}
983
984bg.ecard.DomTargets.prototype.find = function(selector, returnDomTarget) {
985
986}
987
988bg.ecard.DomTargets.prototype.findAll = function(selector) {
989
990}
991
992bg.ecard.DomTargets.prototype.removeClass = function(className) {
993
994}
995
996bg.ecard.DomTargets.prototype.addClass = function(className) {
997
998}
999
1000bg.ecard.DomTargets.prototype.setData = function(dataObj) {
1001
1002	for (var i=0; i<this.targetDOMs.length; i++) {
1003		this.targetDOMs[i].setData(dataObj);
1004	}
1005}
1006bg.ecard.DomTargets.prototype.removeData = function(dataId) {
1007
1008	// console.log( this, 'removeData()' );
1009
1010	for (var i=0; i<this.targetDOMs.length; i++) {
1011		console.log(i);
1012		this.targetDOMs[i].removeData(dataId);
1013	}
1014}
1015
1016bg.ecard.DomTargets.prototype.remove = function() {
1017
1018}
1019
1020//bg.ecard.utils.registerJS('bg.ecard.DomTargets.js');
1021
1022
1023/* ==================== vendor/08-ui-element-class.js ==================== */
1024;
1025/* File: Compat vendor - bg.ecard.UIElementClass */
1026/* ДОСЛОВНО копие от: bg.ecard\main\ui\bg.ecard.UIElementClass.js. НЕ РЕДАКТИРАЙ.
1027 * Базовият клас на кампанийните data-element-type елементи (extendClass(UIElementClass, this)).
1028 * Ползва вече наличните vendored: utils.extendClass, BaseElement, EventDispatcher + shim фасадите
1029 * (app.events / app.network / app.interface / appConfig).
1030 * ОТЛОЖЕНИ опционални зависимости (идват със следващи vendor късове; guarded или само на определен path):
1031 *   bg.ecard.Timer         — this.init() / timeout/interval/tick/delay (guarded: if (bg.ecard.Timer))
1032 *   bg.ecard.ModuleManager — checkRequire/loadAllScripts (guarded)
1033 *   bg.ecard.Network.Ajax  — this.ajax()  (само ако кампанията вика this.ajax)
1034 *   plural (loose global)  — translate() при object/plural dictionary entry
1035 *   bg.ecard.managersList[managerId].attachComponent — manager handshake (guarded с if) */
1036/*#  bg.ecard.UIElementClass */
1037bg.ecard.UIElementClass = (function () {
1038	var UIElementClass = function (parent, params) {
1039		this.hasBeenInit = false;
1040		this.initTimeId;
1041
1042	};
1043
1044	UIElementClass.prototype.init = function (time) {
1045		if (bg.ecard.UIElementClass.deactiveComponents) return;
1046
1047		if (bg.ecard.Timer) this.timer = new bg.ecard.Timer(this);
1048		//
1049		if (this.holder && this.holder.dataset.elementEnv) {
1050			var device = bg.ecard.app.interface.parser.device.type;
1051			var elementEnv = this.holder.dataset.elementEnv;
1052			var hasMatch = elementEnv.indexOf(bg.ecard.app.interface.env.id) != -1;
1053			//var hasMatch = false;
1054			var map = {
1055				dt: "desktop",
1056				mbl: "mobile",
1057				tbl: "tablet"
1058			}
1059
1060			if (!hasMatch && device) {
1061				var devices = elementEnv.indexOf(",") != -1 ? elementEnv.split(",") : [elementEnv];
1062				for (var i = 0; i < devices.length; i++) {
1063					if (map[devices[i]] == device) {
1064						hasMatch = true;
1065					}
1066				}
1067			}
1068			//if( device && device.indexOf(  ))
1069
1070			if (!hasMatch) return;
1071		}
1072
1073		if (this.holder && this.holder.dataset.viewport != undefined) {
1074			var self = this;
1075
1076			this.initTimeId = setTimeout(function () {
1077				self.addLoader();
1078
1079				bg.ecard.app.events.bind('viewport:show:' + self.holder.dataset.hasInit, self, "inViewport");
1080				bg.ecard.app.events.trigger("viewport:add", self.holder);
1081			}, 2000);
1082		} else {
1083			this.initTimeId = setTimeout(checkRequire.bind(this), time == undefined ? 0 : time);
1084		}
1085	}
1086
1087	UIElementClass.prototype.socketSend = function (msg) {
1088		this._socket_buffer = this._socket_buffer || [];
1089
1090		this._socketSub = true;
1091
1092		if (msg) {
1093			let text = JSON.stringify(msg);
1094			if (this._socket_buffer.indexOf(text) == -1) {
1095				this._socket_buffer.push(text);
1096			}
1097		}
1098
1099		//&& bg.ecard.app.interface.env.environment == "desktop"
1100
1101		if (!bg.ecard.app.network.active.socket[bg.ecard.appConfig.appParams.websocket_name] || !bg.ecard.app.network.active.socket[bg.ecard.appConfig.appParams.websocket_name].state || !bg.ecard.app.network.active.socket[bg.ecard.appConfig.appParams.websocket_name].state.active) {
1102			bg.ecard.app.events.unbind('net.Socket.' + bg.ecard.appConfig.appParams.websocket_name + '.open', this, 'onConnect');
1103			bg.ecard.app.events.bind('net.Socket.' + bg.ecard.appConfig.appParams.websocket_name + '.open', this, 'onConnect');
1104			bg.ecard.app.events.unbind('broadcast.socket.open', this, 'onConnect');
1105			bg.ecard.app.events.bind('broadcast.socket.open', this, 'onConnect');
1106		} else {
1107			this.onConnect();
1108		}
1109
1110	};
1111
1112	UIElementClass.prototype.translate = function (key) {
1113		let dictionery = bg.ecard.appConfig.appParams.translate;
1114
1115		if (dictionery[key]) {
1116			if (typeof dictionery[key] == "string") {
1117				let str = dictionery[key];
1118
1119				for (let i = 1; i < arguments.length; i++) {
1120					let ind = i - 1;
1121					str = str.replace("{" + ind + "}", arguments[i]);
1122				}
1123
1124				return str;
1125			} else if (typeof dictionery[key] == "object") {
1126				let val = arguments[1]
1127				let addBefore = false;
1128
1129				if (typeof arguments[1] == "object") {
1130					val = arguments[1].val;
1131					addBefore = arguments[1];
1132				}
1133
1134				return plural(dictionery[key], val, addBefore);
1135			}
1136
1137		} else {
1138			// console.log("MISSING KEY", key)
1139		}
1140
1141		return key;
1142		// bg.ecard.app.translate
1143	}
1144
1145	UIElementClass.prototype.onConnect = function () {
1146		for (var index = 0; index < this._socket_buffer.length; index++) {
1147
1148			bg.ecard.app.network.active.socket[bg.ecard.appConfig.appParams.websocket_name].send(this._socket_buffer[index]);
1149		}
1150
1151		this._socket_buffer = [];
1152
1153		bg.ecard.app.events.unbind('net.Socket.' + bg.ecard.appConfig.appParams.websocket_name + '.open', this, 'onConnect');
1154		bg.ecard.app.events.unbind('broadcast.socket.open', this, 'onConnect');
1155	}
1156
1157	// т.3: shared registry — tracks scripts currently loading (src → [callbacks])
1158	var _pendingScripts = {};
1159
1160	function loadAllScripts(scripts) {
1161		var self = this;
1162
1163		// guard against falsy/missing src
1164		if (!scripts[0]) {
1165			self.hasBeenInit = true;
1166			if (bg.ecard.ModuleManager) bg.ecard.ModuleManager.process(self);
1167			self.initReady.call(self);
1168			return;
1169		}
1170
1171		var src = scripts[0];
1172		var normalizedSrc = src.split('?')[0];
1173		var rest = scripts.slice(1); // т.5: no mutation of input array
1174
1175		function proceed() {
1176			if (rest.length > 0) {
1177				loadAllScripts.call(self, rest);
1178			} else {
1179				self.hasBeenInit = true;
1180				if (bg.ecard.ModuleManager) bg.ecard.ModuleManager.process(self); // т.1: self not this
1181				self.initReady.call(self);
1182			}
1183		}
1184
1185		// already fully loaded (not mid-load)
1186		if (!_pendingScripts[normalizedSrc] && isScriptAlreadyAdded(src)) {
1187			proceed();
1188			return;
1189		}
1190
1191		// currently loading — queue callback instead of double-appending
1192		if (_pendingScripts[normalizedSrc]) {
1193			_pendingScripts[normalizedSrc].push(proceed);
1194			return;
1195		}
1196
1197		_pendingScripts[normalizedSrc] = [proceed];
1198
1199		var script = document.createElement('script');
1200		script.onload = function () {
1201			var callbacks = _pendingScripts[normalizedSrc] || [];
1202			delete _pendingScripts[normalizedSrc];
1203			callbacks.forEach(function (cb) { cb(); });
1204		};
1205		script.onerror = function () { // т.2: prevent silent hang on load failure
1206			delete _pendingScripts[normalizedSrc];
1207		};
1208		script.src = src;
1209		self.internalScripts.push(script);
1210		document.head.appendChild(script);
1211	}
1212
1213	function isScriptAlreadyAdded(newSrc) {
1214		var normalizedNew = newSrc.split('?')[0];
1215		// т.3: a script in _pendingScripts is in DOM but not yet executed
1216		if (_pendingScripts[normalizedNew]) return false;
1217		var scripts = document.getElementsByTagName('script');
1218		for (var i = 0; i < scripts.length; i++) {
1219			if (scripts[i].src.split('?')[0] === normalizedNew) {
1220				return true;
1221			}
1222		}
1223		return false;
1224	}
1225
1226	function checkRequire() {
1227		if (this.useResize)
1228			bg.ecard.app.events.bind('windowResized', this, "resize");
1229
1230		if (this.require && this.require.length) {
1231			this.internalScripts = [];
1232			loadAllScripts.call(this, Array.isArray(this.require) ? this.require : [this.require]);
1233		} else {
1234
1235			if (this.holder && (managerId = this.holder.dataset.managerId)) {
1236				if (bg.ecard.managersList[managerId]) {
1237					bg.ecard.managersList[managerId].attachComponent(this)
1238				}
1239			}
1240			if (bg.ecard.ModuleManager) bg.ecard.ModuleManager.process(this)
1241			this.initReady();
1242			this.hasBeenInit = true;
1243
1244		}
1245	}
1246
1247	// END END END
1248
1249
1250
1251	UIElementClass.prototype.inViewport = function () {
1252		bg.ecard.app.events.unbind('viewport:show:' + this.holder.dataset.hasInit, this, "inViewport");
1253
1254		checkRequire.call(this);
1255		//this.initReady();
1256	}
1257
1258	UIElementClass.prototype.initReady = function () { }
1259	UIElementClass.prototype.resize = function () { }
1260
1261	UIElementClass.prototype.params = {
1262		type: 'UIElementClass',
1263		initClassFunc: 'initClassUIElement'
1264	}
1265
1266	UIElementClass.prototype.initClassUIElement = function () {
1267
1268		if (!this.activeIn) {
1269			this.activeIn = [];
1270		}
1271
1272		bg.ecard.utils.extendClass(bg.ecard.BaseElement, this);
1273
1274		if (!this.events) {
1275			this.events = new bg.ecard.EventDispatcher(this);
1276		}
1277
1278		if (this.params.events) {
1279			for (var i in this.params.events) {
1280				var currEvent = this.params.events[i];
1281				this.events.bind(i, currEvent.caller, currEvent.funcName);
1282			}
1283		}
1284
1285		this.events.bind('underManagement', this, 'processAddedToManager');
1286	};
1287
1288	UIElementClass.prototype.processAddedToManager = function (manager) {
1289
1290		this.activeIn.push(manager);
1291	}
1292
1293	UIElementClass.prototype.addLoader = function () {
1294		if (!this.loaderHolder && this.holder && this.holder.dataset.loader) {
1295			var selector = this.holder.dataset.loader;
1296			if (selector == "this") {
1297				this.loaderHolder = this.holder;
1298			} else if (selector == "parent") {
1299				this.loaderHolder = this.holder.parentNode;
1300			} else if (selector.indexOf("#") != -1) {
1301				this.loaderHolder = document.querySelector(selector);
1302			} else {
1303				this.loaderHolder = this.holder.closest(selector);
1304			}
1305		}
1306		if (this.loaderHolder)
1307			this.loaderHolder.classList.add('loading');
1308	}
1309
1310	UIElementClass.prototype.removeLoader = function () {
1311		if (this.loaderHolder) this.loaderHolder.classList.remove('loading')
1312	}
1313
1314	UIElementClass.prototype.callAction = function (data) {
1315		setTimeout(function () {
1316			bg.ecard.app.events.trigger('action:start', data);
1317		}, 0);
1318	}
1319
1320	UIElementClass.prototype.onDestroy = function (manager) {
1321		if (this.holder && this.holder.dataset && this.holder.dataset.viewport) {
1322			bg.ecard.app.events.unbind('viewport:show:' + this.holder.dataset.hasInit, this, "inViewport");
1323			bg.ecard.app.events.trigger("viewport:remove", this.holder);
1324		}
1325
1326		if (this.useResize)
1327			bg.ecard.app.events.unbind('windowResized', this, "resize");
1328
1329		if (this.hasBeenInit) {
1330			this.destroy();
1331		}
1332
1333		if (this.autoDestroyScript && this.internalScripts) {
1334			for (var index = 0; index < this.internalScripts.length; index++) {
1335				document.head.removeChild(this.internalScripts[index]);
1336			}
1337		}
1338
1339		if (this.initTimeId)
1340			clearTimeout(this.initTimeId);
1341		if (this._socketSub) {
1342			bg.ecard.app.events.unbind('net.Socket.' + bg.ecard.appConfig.appParams.websocket_name + '.open', this, 'onConnect');
1343			bg.ecard.app.events.unbind('broadcast.socket.open', this, 'onConnect');
1344
1345		}
1346
1347		//script[i].parentNode.remove(script[i])
1348
1349		bg.ecard.app.events.unbindAll(this)
1350		if (this.timer && this.timer.destroy) this.timer.destroy();
1351	}
1352
1353	UIElementClass.prototype.linkLoad = function (complete) {
1354		this._relLinks = document.querySelectorAll("link");
1355
1356		for (var i = 0; i < this._relLinks.length; i++) {
1357			this._relLinks[i].onload = function () {
1358				//console.log("load");
1359				window.dispatchEvent(new Event("resize"));
1360			}
1361
1362			//
1363			//console.log(this._reflink);
1364
1365		}
1366	}
1367
1368	UIElementClass.prototype.select = function (selector) {
1369		if (this.holder) return this.holder.querySelector(selector);
1370	}
1371
1372	UIElementClass.prototype.selectAll = function (selector) {
1373		if (this.holder) return Array.from(this.holder.querySelectorAll(selector));
1374	}
1375
1376	UIElementClass.prototype.ajax = function (data) {
1377		if (!data.caller) data.caller = this;
1378
1379		return new bg.ecard.Network.Ajax(data);
1380	}
1381
1382	UIElementClass.prototype.bind = function (event, callback) {
1383		bg.ecard.app.events.bind(event, this, callback);
1384	}
1385
1386	UIElementClass.prototype.unbind = function (event, callback) {
1387		bg.ecard.app.events.unbind(event, this, callback);
1388	}
1389
1390	UIElementClass.prototype.trigger = function (event, data1, data2) {
1391		bg.ecard.app.events.trigger(event, data1, data2);
1392	}
1393
1394	UIElementClass.prototype.timeout = function (callback, seconds, ...args) {
1395		return this.timer.timeout(callback, seconds, ...args)
1396	}
1397
1398	UIElementClass.prototype.interval = function (callback, seconds, ...args) {
1399		return this.timer.interval(callback, seconds, ...args)
1400	}
1401
1402	UIElementClass.prototype.tick = function (callback, seconds = 1, times = 1, onComplete, ...args) {
1403		return this.timer.tick(callback, seconds = 1, times = 1, onComplete, ...args)
1404	}
1405
1406	UIElementClass.prototype.update = function (callback) {
1407
1408	}
1409
1410	UIElementClass.prototype.delay = function (callback, seconds, groupID, ...args) {
1411		return this.timer.delay(callback, seconds, groupID, ...args)
1412	}
1413
1414	UIElementClass.prototype.clearTimer = function (timer) {
1415		this.timer.clear(timer);
1416	}
1417
1418	UIElementClass.prototype.destroy = function (manager) { }
1419
1420	return UIElementClass;
1421}());
1422
1423
1424/* ==================== vendor/09-timer.js ==================== */
1425;
1426/* File: Compat vendor - bg.ecard.Timer */
1427/* ДОСЛОВНО (байт-за-байт) копие от: bg.ecard\main	imer	imer.js. НЕ РЕДАКТИРАЙ.
1428 * gsap-базиран (TweenMax + TweenMax.ticker) — външни глобаÐ
1428»Ð¸, налични на реалните страници.
1429 * ЗАБЕЛЕЖКА: onUpdate() реферира GamePauseManager (немигриран) БЕЗ guard — задейства се само на
1430 * update()/ticker path; timeout/interval/tick/delay не го пипат. Ред "static <id> = []" съдържа
1431 * не-ASCII идентификатор в оригинала (Timer.updateList го чете) — пазен байт-идентично. */
1432/*# Timer */
1433bg.ecard.Timer = (function (){
1434    return class Timer {
1435
1436    static dif = 1000 / 60;
1437    static minDif = (1000 / 60) - 2;
1438
1439    static FPS = 0;
1440    static lags = [];
1441    static fpsLength = 60;
1442    static fpsLevel;
1443    static  = [];
1444    static isPaused = false;
1445
1446    reqUpdateEvent = true;
1447
1448    _list = [];
1449    _updateList = [];
1450    _delayIDS = {};
1451
1452    constructor(context) {
1453        this.context = context;
1454    }
1455
1456    timeout(callback, seconds, ...args) {
1457        let params = args;
1458
1459        let tw = TweenMax.delayedCall(seconds, () => {            
1460            this.clear(tw)
1461
1462            if (typeof callback == "function")
1463                callback.apply(this.context, params);
1464            else {
1465                console.log(callback, seconds, args)
1466            }
1467        })
1468
1469        // GamePauseManager.addToActive(tw);
1470        this._list.push(tw);
1471        return tw;
1472    }
1473
1474    update(callback, speed = {}) {
1475        this._updateList.push({
1476            cbc: callback,
1477            speed: speed
1478        })
1479
1480        // Timer.updateList.push(this)
1481
1482        if (this.reqUpdateEvent) {
1483            delete this.reqUpdateEvent;
1484            this._up = this.onUpdate.bind(this);
1485            TweenMax.ticker.add(this._up)
1486        }
1487    }
1488
1489    onUpdate(time, deltaTime, frame) {
1490        if (GamePauseManager.isPaused) return;
1491
1492        for (let i = 0; i < this._updateList.length; i++) { //TODO check for mutate array
1493            let obj = this._updateList[i]
1494            let speedFactor = 1;
1495            
1496            obj.cbc.call(this.context, time, deltaTime, frame, speedFactor)
1497        }
1498    }
1499
1500    interval(callback, seconds, ...args) {
1501        let  params = args;
1502       
1503        const tw = TweenMax.delayedCall(seconds, () => {
1504            tw.restart(true);
1505            callback.apply(this.context, params);
1506        });
1507
1508        this._list.push(tw);
1509
1510        return tw;
1511    }
1512
1513    tick(callback, seconds = 1, times = 1, onComplete, ...args) {
1514        let params = args;
1515
1516        const tw = TweenMax.delayedCall(seconds, tick.bind(this));
1517        let count = 0;
1518
1519        function tick() {
1520            if (--times >= 0) {
1521                if (times == 0) this.clear(tw);
1522                else tw.restart(true);
1523                const p = [++count].concat(params);
1524                callback.apply(this.context, p);
1525                if (times == 0 && onComplete) onComplete.apply(this.context, p);
1526            }
1527        }
1528
1529        this._list.push(tw);
1530
1531        return tw;
1532    }
1533
1534    delay(callback, seconds, groupID, params = []) {
1535        if (this._delayIDS[groupID]) {
1536            this._delayIDS[groupID].restart(true);
1537            return this._delayIDS[groupID];
1538        }
1539
1540        const del = TweenMax.delayedCall(seconds, () => {
1541            this._delayIDS[groupID];
1542            this.clear(del)
1543            callback.apply(this.context, params);
1544        });
1545
1546        this._delayIDS[groupID] = del;
1547        this._list.push(del);
1548        return del;
1549    }
1550
1551    clear(timer) {
1552
1553        if (timer && timer.kill) timer.kill();
1554
1555        for (let key in this._delayIDS) {
1556            if (this._delayIDS[key] == timer) {
1557                delete this._delayIDS[key];
1558            }
1559        }
1560
1561        for (let i = this._list.length - 1; i > -1; i--) {
1562            if (timer == this._list[i]) {
1563                timer.kill();
1564                this._list.splice(i, 1);
1565                timer = null;
1566                return true;
1567            }
1568        }
1569
1570        let removeUpdate = false;
1571        for (let i = this._updateList.length - 1; i > -1; i--) {
1572            if (timer == this._updateList[i].cbc) {
1573                this._updateList.splice(i, 1);
1574                removeUpdate = true;
1575                // return true;
1576            }
1577
1578        }
1579
1580        if (removeUpdate) {
1581            if (!this._updateList.length && this._up) {
1582                this.reqUpdateEvent = true
1583                // TweenMax.ticker.removeEventListener("tick", this._up, this);
1584                TweenMax.ticker.remove(this._up)
1585            }
1586
1587        }
1588    }
1589
1590    clearTimeout(timer) {
1591        this.clear(timer);
1592    }
1593
1594    clearInterval(timer) {
1595        this.clear(timer);
1596    }
1597
1598    clearUpdate(timer) {
1599        this.clear(timer);
1600    }
1601
1602    clearTick(timer) {
1603        this.clear(timer);
1604    }
1605
1606    clearAll() {
1607        this._list.forEach(e => e.kill())
1608
1609        this._list = [];
1610
1611        for (let key in this._delayIDS) {
1612            this._delayIDS[key].kill();
1613        }
1614
1615        this._updateList = [];
1616        TweenMax.ticker.remove(this._up)
1617
1618        for (let i = Timer.updateList.length - 1; i >= 0; i--) {
1619            if (Timer.updateList[i]) {
1620                Timer.updateList.splice(i, 1)
1621            }
1622        }
1623
1624        //TweenMax.ticker.removeEventListener("tick", this.onUpdate, this);
1625    }
1626
1627    static pause() {
1628
1629    }
1630
1631    static resume() {
1632
1633    }
1634
1635    destroy() {
1636        this.clearAll();
1637
1638    }
1639}
1640
1641})();
1642
1643/* ==================== vendor/10-helpers.js ==================== */
1644;
1645/* File: Compat vendor - bg.ecard.helpers */
1646/* ДОСЛОВНО (байт-за-байт) копие от: bg.ecard\main�g.ecard.Helpers.js. НЕ РЕДАКТИРАЙ.
1647 * bg.ecard.helpers.* (tryParseJSONObject, hasTouchScreen, getFullSize, getPosition, isOutOfScreen, …)
1648 * — ползван от кампанийните класове (ShowHide/DropDown/
1648Marquee и др.). Самодостатъчен обект-литерал. */
1649/*#  bg.ecard.helpers  */
1650bg.ecard.helpers = { 
1651    hasTouchScreen: () =>  {
1652        let hasTouchScreen = false;
1653        if ("maxTouchPoints" in navigator) {
1654            hasTouchScreen = navigator.maxTouchPoints > 0;
1655        } else if ("msMaxTouchPoints" in navigator) {
1656            hasTouchScreen = navigator.msMaxTouchPoints > 0;
1657        } else {
1658            let mQ = window.matchMedia && matchMedia("(pointer:coarse)");
1659            if (mQ && mQ.media === "(pointer:coarse)") {
1660                hasTouchScreen = !!mQ.matches;
1661            } else if ('orientation' in window) {
1662                hasTouchScreen = true; // deprecated, but good fallback
1663            } else {
1664                // Only as a last resort, fall back to user agent sniffing
1665                let UA = navigator.userAgent;
1666                hasTouchScreen = (
1667                    /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
1668                    /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA)
1669                );
1670            }
1671        }
1672        return hasTouchScreen;
1673    },
1674    getFullSize: (el) => {
1675        const elWidth = el.offsetWidth;
1676        const elHeight = el.offsetHeight;
1677
1678        const style = window.getComputedStyle(el);
1679        const marginWidth = parseFloat(style.marginLeft) + parseFloat(style.marginRight);
1680        const marginHeight = parseFloat(style.marginTop) + parseFloat(style.marginBottom);
1681
1682        const elFullWidth = elWidth + marginWidth;
1683        const elFullHeight = elHeight + marginHeight;
1684
1685        return { width: elFullWidth, height: elFullHeight }
1686    },
1687    getPosition: (el) => {
1688        const top = window.scrollY + el.getBoundingClientRect().top;
1689        const bottom = (top + el.offsetHeight);
1690        const left = window.scrollX + el.getBoundingClientRect().left;
1691        const right = (left + el.offsetWidth);
1692        const centerY = (top + el.offsetHeight / 2);
1693        const centerX = (left + el.offsetWidth / 2);
1694
1695        return { top, bottom, left, right, centerY, centerX }
1696    },
1697    isOutOfScreen: (el, offset) => {
1698        /* COMPAT-EDIT: оригиналът има `let offset` (пресенчва параметъра → ES6 SyntaxError).
1699         * В продукция Babel го сваля до `var`, което прави redeclare-а легален. Тук правим
1700         * същото ръчно (поведенчески идентично), защото build.js-ът е чист concat без Babel. */
1701        var offset = offset ? offset : 0;
1702        const rect = el.getBoundingClientRect();
1703        const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
1704        const viewWidth = Math.max(document.documentElement.clientWidth, window.innerWidth);
1705        const screen = rect.top < 0 || rect.bottom > viewHeight || rect.left < 0 || rect.right > viewWidth;
1706        const height = rect.top < 0 || rect.bottom > viewHeight;
1707        const width = rect.left < 0 || rect.right > viewWidth;
1708        const top = rect.top < 0;
1709        const bottom = rect.bottom > viewHeight;
1710        const bottomOutScreen = (rect.bottom - offset) > viewHeight || rect.bottom < 0;
1711        const left = rect.left < 0;
1712        const right =  rect.right > viewWidth;
1713
1714        return { screen, height, width, top, bottom, bottomOutScreen, left, right }
1715    },
1716    isOutOfParent: (parentEl, el, offset) => {
1717        var offset = offset ? offset : 0; /* COMPAT-EDIT: let→var (Babel-еквивалент, виж по-горе) */
1718        const parentRect = parentEl.getBoundingClientRect();
1719        const rect = el.getBoundingClientRect();
1720        const screen = rect.top < parentRect.top || rect.bottom > parentRect.bottom || rect.left < parentRect.left || rect.right > parentRect.right;
1721        const height = rect.top < parentRect.top || rect.bottom > parentRect.bottom;
1722        const width = rect.left < parentRect.left || rect.right > parentRect.right;
1723        const top = rect.top < parentRect.top;
1724        const bottom = rect.bottom > parentRect.bottom;
1725        const bottomOutScreen = (rect.bottom - offset) > parentRect.bottom;
1726        const left = rect.left < parentRect.left;
1727        const right =  rect.right > parentRect.right;
1728
1729        return { screen, height, width, top, bottom, bottomOutScreen, left, right }
1730    },
1731    isTouchScreenDevice: () => {
1732        let isTouchScreenDevice = false;
1733        if ("maxTouchPoints" in navigator) {
1734            isTouchScreenDevice = navigator.maxTouchPoints > 0;
1735        } else if ("msMaxTouchPoints" in navigator) {
1736            isTouchScreenDevice = navigator.msMaxTouchPoints > 0;
1737        } else {
1738            let mQ = window.matchMedia && matchMedia("(pointer:coarse)");
1739            if (mQ && mQ.media === "(pointer:coarse)") {
1740                isTouchScreenDevice = !!mQ.matches;
1741            } else if ('orientation' in window) {
1742                isTouchScreenDevice = true; // deprecated, but good fallback
1743            } else {
1744                // Only as a last resort, fall back to user agent sniffing
1745                let UA = navigator.userAgent;
1746                isTouchScreenDevice = (
1747                    /\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
1748                    /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA)
1749                );
1750            }
1751        }
1752        return isTouchScreenDevice;
1753    },
1754    isInScreen: (el, threshold) => {
1755        if(!threshold) threshold = 0;
1756        const thresholdWidth = el.offsetWidth * threshold;
1757        const thresholdHeight = el.offsetHeight * threshold
1758        let rect = el.getBoundingClientRect();
1759        return ((rect.bottom - thresholdHeight) >= 0 && (rect.right - thresholdWidth) >= 0 && (rect.top + thresholdHeight) <= (window.innerHeight || document.documentElement.clientHeight) && (rect.left + thresholdHeight) <= (window.innerWidth || document.documentElement.clientWidth));
1760    },
1761    isVisible: (el) => {
1762        return  el.clientWidth !== 0 && el.clientHeight !== 0 && (el.style.opacity !== '' ? parseFloat(el.style.opacity) > 0 : true);
1763    },
1764    tryParseJSONObject: (jsonString) => {
1765        try {
1766            var o = JSON.parse(jsonString);
1767            if (o && typeof o === "object") { return o; }
1768        }
1769        catch (e) {}
1770        return false;
1771    },
1772    randomNumberBetween(min, max) {
1773        return Math.random() * (max - min + 1) + min;
1774    },
1775    fillFields: (settings) => {
1776        
1777        if(!settings || !settings.fields || !settings.container) return;
1778        try {
1779            for (const fieldSelector in settings.fields) {
1780                let fieldValue = settings.fields[fieldSelector].value || null;
1781                let fieldsOfType = settings.container.querySelectorAll(fieldSelector);
1782                
1783                if(fieldsOfType) {
1784                    for (const fieldOfType of fieldsOfType) {
1785                        fieldOfType.innerHTML = fieldValue;
1786                    }
1787                }           
1788            }
1789        } catch (error) {
1790            console.log(error);
1791        }
1792    },
1793    exitFullScreen: () => {
1794        try {
1795            if(document.webkitExitFullscreen) {
1796                document.webkitExitFullscreen().then((data) => {}).catch((err) => {});
1797            } else if (document.fullscreenElement) {
1798                document.exitFullscreen().then((data) => {}).catch((err) => {});
1799            }
1800        } catch (error) {
1801            // console.log(error);
1802        }
1803    },
1804    jsonToQueryParams: (json) => {
1805        if(typeof json != 'object') return "";
1806        let queryParams = "";
1807        Object.keys(json).forEach((key, index, arr) => {
1808            if(index == (arr.length - 1)) {
1809                queryParams += encodeURIComponent(key) + "=" + encodeURIComponent(json[key]);
1810            } else {
1811                queryParams += encodeURIComponent(key) + "=" + encodeURIComponent(json[key]) + "&";
1812            }
1813        })
1814        return queryParams;
1815        
1816    },
1817   
1818    loadScriptsParallel: (filesToLoad, callback) => {
1819
1820        if (!filesToLoad || !filesToLoad.js || !filesToLoad.js.length) {
1821            callback();
1822            return;
1823        }
1824
1825        var scripts = filesToLoad.js;
1826        var loadedCount = 0;
1827        var hasError = false;
1828
1829        function onComplete() {
1830            loadedCount++;
1831            if (loadedCount === scripts.length && !hasError) {
1832                callback();
1833            }
1834        }
1835
1836        function onError(src) {
1837            if (hasError) return;
1838            hasError = true;
1839            console.error('Failed to load script:', src);
1840        }
1841
1842        for (var i = 0; i < scripts.length; i++) {
1843            (function(src) {
1844                var script = document.createElement('script');
1845                script.type = 'text/javascript';
1846                script.src = src;
1847                script.async = true;
1848                script.onload = function() {
1849                    onComplete();
1850                };
1851                script.onerror = function() {
1852                    onError(src);
1853                };
1854                document.head.appendChild(script);
1855            })(scripts[i]);
1856        }
1857    }
1858}
1859
1860/* ==================== vendor/11-network-ajax.js ==================== */
1861;
1862/* File: Compat vendor - bg.ecard.Network.Ajax */
1863/* ДОСЛОВНО (байт-за-байт) копие от: bg.ecard\main�g.ecard.Network.Ajax.js. НЕ РЕДАКТИРАЙ.
1864 * Суров XHR. Ползва shim фасадите: bg.ecard.app.events (ajax:send/ajax:receive) + bg.ecard.app.error.
1865 * Авто-добавя is_ajax=1 (освен skipIsAjax) + _cache=<ts>. Locker пази дублирани едновременни заявки.
1866 * Callback контракт: params.result / params.error (име-на-метод стринг ИЛИ функция) върху params.caller.
1867 * ЗАБЕЛЕЖКА: initFormData() ползва jQuery ($) — само за multipart (params.formData). init() (чист XHR)
1868 * е пътят на обикновените форми/награди и НЕ иска jQuery. */
1869
1870/*# bg.ecard.Network.Ajax */
1871if (!bg) {
1872    bg = {};
1873}
1874if (!bg.ecard) {
1875    bg.ecard = {};
1876}
1877if (!bg.ecard.Network) {
1878    bg.ecard.Network = {};
1879}
1880
1881bg.ecard.Network.Ajax = function (params, parent) {
1882    this.params = params;
1883    this.params.type = 'bg.ecard.Network.Ajax';
1884    this.params.id = this.params.url;
1885    //  this.params.sync = this.params.sync;
1886    this.params.parent = parent;
1887
1888    this.inProgress = false;
1889    this.reconnectCount = 0;
1890    this.retryCount = 0;
1891    this.header = this.params.header || 'application/x-www-form-urlencoded';
1892    // this.method = "GET";//params.method || "POST";
1893    this.method = params.method || "POST";
1894
1895    if (this.params.formData) {
1896        this.initFormData();
1897    } else
1898        this.init();
1899}
1900
1901bg.ecard.Network.Ajax.locker = {};
1902
1903bg.ecard.Network.Ajax.prototype.initFormData = function () {
1904    if (this.req) {
1905        delete this.req;
1906    }
1907
1908    // this.req = new XMLHttpRequest();
1909
1910    // this.req.addEventListener('readystatechange', this.processState);
1911    // this.req.jsTarget = this;
1912
1913    var url = this.params.url.split('?');
1914
1915    // bg.ecard.app.events.trigger("ajax:send");
1916
1917    // this.req.open(this.method, url[0], true);
1918
1919    // this.req.setRequestHeader('Content-type', this.header);
1920    // this.req.setRequestHeader('Content-type', "false");
1921    // this.inProgress = true;
1922
1923    // this.req.send(this.params.formData);
1924
1925    $.ajax({
1926        url: url[0],
1927        data: this.params.formData,
1928        processData: false,
1929        contentType: false,
1930        type: 'POST',
1931        success: function (data) {
1932            console.log(data);
1933            this.params.processSuccess();
1934        }.bind(this)
1935    })
1936}
1937
1938bg.ecard.Network.Ajax.prototype.init = function () {
1939    if (this.req) {
1940        delete this.req;
1941    }
1942
1943    var url = this.params.url.split('?');
1944    var data = "";
1945    if (url.length == 1) { } else {
1946        // var spl = url[1].split('&');
1947        // if (spl.length > 1) {
1948        // } else {
1949        data += url[1];
1950        //data += "&";
1951        //}
1952    }
1953
1954    if (!this.params.data) {
1955        if (!this.params.skipIsAjax)
1956            data = 'is_ajax=1';
1957    } else {
1958        if (this.params.data == "" || this.params.data.charAt(0) == "&") {
1959            if (this.params.data) {
1960                data += this.params.data;
1961                if (!this.params.skipIsAjax) {
1962                    data += '&is_ajax=1';
1963                }
1964
1965            } else {
1966                data = 'is_ajax=1';
1967            }
1968        } else {
1969            if (data != "")
1970                data += "&" + this.params.data;
1971            else {
1972                data += this.params.data;
1973            }
1974            if (!this.params.skipIsAjax)
1975                data += '&is_ajax=1';
1976        }
1977    }
1978
1979    this.lockKey = url[0] + data;
1980
1981    //console.log(bg.ecard.Network.Ajax.locker)
1982
1983    if (bg.ecard.Network.Ajax.locker[this.lockKey]) {
1984        return;
1985    }
1986
1987    bg.ecard.Network.Ajax.locker[this.lockKey] = true;
1988
1989    data += "&_cache=" + new Date().getTime();
1990
1991    this.req = new XMLHttpRequest();
1992    this.req.addEventListener('readystatechange', this.processState);
1993    this.req.jsTarget = this;
1994
1995    //console.log("ajax===", url[0], data);
1996
1997    // var files;
1998    // if (this.params.caller && (files = this.params.caller.holder.querySelectorAll("[type=file]"))) {
1999    //     bg.ecard.Network.Ajax.prototype.getFormData(data, files, this.params.caller.holder)
2000    // }
2001
2002    bg.ecard.app.events.trigger("ajax:send");
2003
2004    if (this.method.toUpperCase() == "POST") {
2005        this.req.open(this.method, url[0], true);
2006    } else {
2007        this.req.open(this.method, data ? url[0] + "?" + data : url[0], true);
2008    }
2009
2010    //this.req.timeout = 10000;
2011    this.req.setRequestHeader('Content-type', this.header);
2012    this.inProgress = true;
2013
2014    this.req.send(data);
2015
2016    // console.log("::CLEAR ALL COOKIES::")
2017    // var cookies = document.cookie.split("; ");
2018    // console.log(cookies)
2019    // for (var c = 0; c < cookies.length; c++) {
2020    //    // var d = window.location.hostname.split(".");
2021
2022    // //      while (d.length > 0) {
2023    // //     //     // var cookieBase = encodeURIComponent(cookies[c].split(";")[0].split("=")[0]) + '=; expires=Thu, 01-Jan-1970 00:00:01 GMT; domain=' + d.join('.') + ' ;path=';
2024    // //     //     var cookieBase = encodeURIComponent(cookies[c].split(";")[0].split("=")[0]) + '=; Max-Age=0;'
2025    // //     //     var p = location.pathname.split('/');
2026    // //     //     document.cookie = cookieBase + '/';
2027    // //     //     while (p.length > 0) {
2028    // //     //         document.cookie = cookieBase + p.join('/');
2029    // //     //         p.pop();
2030    // //     //     };
2031    // //    // deleteCookie(cookies[c].split(";")[0].split("=")[0]);
2032    // //         removeItem(cookies[c].split(";")[0].split("=")[0], "", d.join('.'))
2033    // //         d.shift();
2034    // //     }
2035
2036    //         removeItem(cookies[c].split(";")[0].split("=")[0], "",  window.location.hostname);
2037    // }
2038
2039    // function removeItem(key, path, domain) {
2040    //     console.log(key, domain)
2041    //     document.cookie = encodeURIComponent(key) + 
2042    //                   "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + 
2043    //                   (domain ? "; domain=" + domain : "") + 
2044    //                   (path ? "; path=" + path : "");
2045    // }
2046
2047}
2048
2049bg.ecard.Network.Ajax.prototype.getFormData = function (data, form) {
2050    if (!data) return;
2051    var arr = data.split("&");
2052    var formData = new FormData();
2053    var i = 0;
2054    var files = form.querySelectorAll("[type=file]");
2055    for (; i < arr.length; i++) {
2056        var keys = arr[i].split("=");
2057        if (keys.length == 2)
2058            formData.append(keys[0], keys[1]);
2059    }
2060
2061    for (i = 0; i < files.length; i++) {
2062        formData.append(files[i].name, files[i].files[0]);
2063        // console.log(files[i], files[i].files[0])
2064    }
2065
2066    formData.append("is_ajax", 1);
2067
2068    // console.log(form);
2069    // console.log(files);
2070
2071    return formData;
2072}
2073
2074bg.ecard.Network.Ajax.prototype.processState = function () {
2075    if (this.readyState === 4) {
2076        if ((this.status === 200) || (this.status === 302)) {
2077            this.jsTarget.processSuccess();
2078        } else {
2079            this.jsTarget.processError(this.status);
2080        }
2081    }
2082}
2083
2084bg.ecard.Network.Ajax.prototype.processError = function (httpErroCode) {
2085
2086    delete bg.ecard.Network.Ajax.locker[this.lockKey];
2087    bg.ecard.app.events.trigger("ajax:receive");
2088    //app.die({errorId: 'network error ' + this.req.status , elementName: this.params.url});
2089    this.inProgress = false;
2090
2091    if (typeof this.params.caller[this.params.error]) {
2092
2093        if (typeof this.params.error == "string")
2094            this.params.caller[this.params.error](httpErroCode);
2095        else {
2096            this.params.error.call(this.params.caller, httpErroCode);
2097        }
2098
2099    } else {
2100        bg.ecard.app.error('ERROR loading ' + this.params.url + ' -- ERROR ' + httpErroCode);
2101    }
2102
2103}
2104
2105bg.ecard.Network.Ajax.prototype.processSuccess = function () {
2106    delete bg.ecard.Network.Ajax.locker[this.lockKey];
2107    bg.ecard.app.events.trigger("ajax:receive");
2108
2109    if (this.params.resultType === 'html') { // request expects HTML responce
2110        responseObj = this.req.responseText;
2111    } else if (this.params.resultType === 'string') {
2112        //responseObj 
2113    } else { // request expects JSON responce
2114        try {
2115            var responseObj = JSON.parse(this.req.responseText);
2116            this.responseObj = responseObj;
2117        } catch (error) {
2118            if (this.params.jsonParseError)
2119                this.params.jsonParseError.call(this.params.caller, error);
2120        }
2121
2122        if (!responseObj) {
2123            console.error('JSON parse error');
2124        }
2125    }
2126
2127    this.inProgress = false;
2128
2129    //  if (this.params.parent.params.triggerAsyncResults) {
2130    if (typeof this.params.result == "string")
2131        setTimeout(this.params.caller[this.params.result].bind(this.params.caller, responseObj), 0);
2132    else {
2133        setTimeout(function () {
2134            this.params.result.call(this.params.caller, responseObj);
2135        }.bind(this), 0);
2136    }
2137    //  } else {
2138    //    this.params.caller[this.params.result]( responseObj );
2139    //  }
2140}
2141
2142bg.ecard.Network.Ajax.serializeForm = function (form) {
2143    if (!form || (form.nodeName !== "FORM" && form.dataset.form == undefined)) {
2144        return;
2145    }
2146
2147    if (form.dataset.form) {
2148        form.elements = form.querySelectorAll("input, textarea, select, button")
2149    }
2150    // }else{
2151    // 	form.elements = form.querySelectorAll( "div:not([data-form]) input, div:not([data-form]) input, div:not([data-form]) textarea, div:not([data-form]) button" );
2152
2153    // }
2154    // console.log(form.elements);
2155
2156    var i, j, q = [];
2157    for (i = form.elements.length - 1; i >= 0; i = i - 1) {
2158        if (form.elements[i].name === "") {
2159            continue;
2160        }
2161        switch (form.elements[i].nodeName) {
2162            case 'INPUT':
2163                switch (form.elements[i].type) {
2164                    case 'text':
2165                        if (form.elements[i].dataset.format == "currency") {
2166                            q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].dataset.sum));
2167                        } else {
2168                            q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
2169                        }
2170                        break;
2171                    case 'hidden':
2172                    case 'password':
2173                    case 'number':
2174                    case 'button':
2175                    case 'reset':
2176                    case 'submit':
2177                    case 'tel':
2178                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
2179                        break;
2180                    case 'checkbox':
2181                    case 'radio':
2182                        if (form.elements[i].checked) {
2183                            q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
2184                        }
2185                        break;
2186                }
2187                break;
2188            case 'file':
2189                break;
2190            case 'TEXTAREA':
2191                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
2192                break;
2193            case 'SELECT':
2194                switch (form.elements[i].type) {
2195                    case 'select-one':
2196                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
2197                        break;
2198                    case 'select-multiple':
2199                        for (j = form.elements[i].options.length - 1; j >= 0; j = j - 1) {
2200                            if (form.elements[i].options[j].selected) {
2201                                q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].options[j].value));
2202                            }
2203                        }
2204                        break;
2205                }
2206                break;
2207            case 'BUTTON':
2208                switch (form.elements[i].type) {
2209                    case 'reset':
2210                    case 'submit':
2211                    case 'button':
2212                        q.push(form.elements[i].name + "=" + encodeURIComponent(form.elements[i].value));
2213                        break;
2214                }
2215                break;
2216        }
2217    }
2218    return q.join("&");
2219}
2220
2221/*
2222
2223bg.ecard.Network.Ajax.prototype.resend = function() {
2224  app.log( this, 'resend()' );
2225
2226  if (this.retryCount < this.params.url.retryCount) {
2227    //		app.warn({errorId:'', elementName:'AJAX returned error '+this.req.status+', resend() triggered'});
2228    this.retryCount++;
2229    app.time.setTimeout(this, 'init', this.params.url.retryTimeout);
2230  } else {
2231    app.sections.load(app.config.sections['NetworkError']).interface.updateLabels(this.params.url);
2232    //		app.clearWarn();
2233    //		this.processError();
2234  }
2235
2236}
2237*/
2238
2239/* ==================== vendor/12-core-currency.js ==================== */
2240;
2241/* File: Compat vendor - bg.ecard core (currency + plural loose globals) */
2242/* ДОСЛОВНО копие от: bg.ecard�g.ecard.js (root), редове 294..EOF. НЕ РЕДАКТИРАЙ.
2243 * Остатъкът от core, ДОПЪЛВА 01-core.js (extendClass). Loose глобаÐ
2243»Ð¸, които кампаниите викат голи:
2244 *   Number.prototype.formatCurrency, parseCurrency, parseCurrencyToNumber, isInt, plural (+ bg.ecard.log).
2245 * Currency функциите четат bg.ecard.appConfig.localizations.balanceData (guarded → shim го подава).
2246 * Зарежда се СЛЕД framework → при евентуална колизия печели compat (детерминистично, по плана P2). */
2247bg.ecard.log = function () { }
2248
2249Number.prototype.formatCurrency = function (c, d, t) {
2250	var n = this, c = isNaN(c = Math.abs(c)) ? 2 : c, d = d == undefined ? "," : d, t = t == undefined ? "." : t, s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
2251	return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
2252};
2253
2254function parseCurrencyToNumber(value, params) {
2255	params = params || {};
2256	// const thousandDelimiter = bg.ecard.appConfig?.localizations?.balanceData?.thousandDelimiter || " ";
2257	// const decimalDelimiter = bg.ecard.appConfig?.localizations?.balanceData?.delimiter || ".";
2258	let thousandDelimiter = " ";
2259	let decimalDelimiter = ".";
2260	if (bg.ecard.appConfig && bg.ecard.appConfig.localizations && bg.ecard.appConfig.localizations.balanceData) {
2261		if (bg.ecard.appConfig.localizations.balanceData.thousandDelimiter) {
2262			thousandDelimiter = bg.ecard.appConfig.localizations.balanceData.thousandDelimiter;
2263		}
2264		if (bg.ecard.appConfig.localizations.balanceData.delimiter) {
2265			decimalDelimiter = bg.ecard.appConfig.localizations.balanceData.delimiter;
2266		}
2267	}
2268
2269	value = String(value).replace(/ /g, "")
2270
2271	if (!params.skipParseFloat && thousandDelimiter == "." && String(value).indexOf(decimalDelimiter) == -1) {
2272		return parseFloat(value)
2273	}
2274
2275	// var isNumber = parseFloat(value) == value && isFinite(value);
2276	// if (isNumber) return parseFloat(value)
2277	// if (typeof value != "string") return ""
2278	let result = "";
2279	for (let i = 0; i < value.length; i++) {
2280		let val = value.charAt(i);
2281		//if (!val.match(/\d/)) {            
2282		if (val == thousandDelimiter)
2283			result += val.replace(thousandDelimiter, "")
2284		else if (val == decimalDelimiter)
2285			result += val.replace(decimalDelimiter, ".")
2286		else {
2287			result += val;
2288		}
2289	}
2290
2291	let indx = result.indexOf(".");
2292	if (indx != -1 && indx > result.length - 2) {
2293		let dif = indx - (result.length - 2);
2294		for (let i = 0; i <= dif; i++) {
2295			result += "0";
2296		}
2297
2298		return Number(result).toFixed(2);
2299	}
2300
2301	return parseFloat(result)
2302}
2303
2304function parseCurrency(value, param) {
2305	param = param || {};
2306	value = parseCurrencyToNumber(value)
2307
2308	// let balanceData = bg.ecard.appConfig?.localizations?.balanceData
2309	let balanceData = {}
2310	if (bg.ecard.appConfig && bg.ecard.appConfig.localizations && bg.ecard.appConfig.localizations.balanceData) {
2311		balanceData = bg.ecard.appConfig.localizations.balanceData;
2312	}
2313	let thousandDelimiter = balanceData.thousandDelimiter || " ";
2314	let decimalDelimiter = balanceData.delimiter || ".";
2315	let digitsAfterDelimiter = balanceData.digitsAfterDelimiter || 2;
2316
2317	if (param.wholeNumber && isInt(value)) {
2318		value = Number(value).toFixed(0)
2319		digitsAfterDelimiter = 0;
2320	}
2321
2322	return Number(value).formatCurrency(digitsAfterDelimiter, decimalDelimiter, thousandDelimiter);
2323
2324}
2325
2326function isInt(n) {
2327	n = Number(n);
2328	return Number(n) === n && n % 1 === 0;
2329}
2330
2331function plural(settings, value, addBefore) {
2332	for (let key in settings) {
2333		if (key.indexOf("-") != -1) {
2334			let spl = key.split("-")
2335			if (value >= spl[0] && value <= spl[1]) return addBefore ? value + " " + settings[key] : settings[key];
2336		} else if (value == key) return addBefore ? value + " " + settings[key] : settings[key];
2337	}
2338	return addBefore ? value + " " + settings.def : settings.def;
2339}
2340
2341/* ==================== vendor/13-uaparser.js ==================== */
2342;
2343/* File: Compat vendor - bg.ecard.UAParser */
2344/* ДОСЛОВНО копие от: bg.ecard\main�g.ecard.UAParser.js. НЕ РЕДАКТИРАЙ.
2345 * Wrapper: връща РЕЗУЛТАТА на външния глобал UAParser() ({browser,device,os,engine}).
2346 * Кампании, които викат голо bg.ecard.UAParser(). Външният UAParser се подава от страницата (vendor.js). */
2347/*# bg.ecard.UAParser */
2348bg.ecard.UAParser = function () {
2349    let ua = UAParser();
2350    // ua.device.type = bg.ecard.appConfig.envDeviceType;
2351    return ua;
2352}
2353
2354
2355/* ==================== vendor/14-cookie.js ==================== */
2356;
2357/* File: Compat vendor - bg.ecard.Cookie */
2358/* ДОСЛОВНО (байт-за-байт) копие от: bg.ecard\main�g.ecard.Cookie.js. НЕ РЕДАКТИРАЙ. Самодостатъчен. */
2359/*#  bg.ecard.Cookie */
2360bg.ecard.Cookie = (function () {
2361
2362    var Cookie = function () {
2363
2364    };
2365
2366    Cookie.prototype.getItem = function (sKey) {
2367        return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
2368    };
2369    Cookie.prototype.setItem = function (sKey, sValue, vEnd, sPath, sDomain, bSecure) {
2370        if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
2371            return false;
2372        }
2373        var sExpires = "";
2374        if (vEnd) {
2375            switch (vEnd.constructor) {
2376                case Number:
2377                    sExpires = vEnd === Infinity ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + vEnd;
2378                    // var date = new Date()
2379                    // date.setDate(400)                    
2380                    // sExpires = "; expires="+date.toGMTString();
2381                    break;
2382                case String:
2383                    sExpires = "; expires=" + vEnd;
2384                    break;
2385                case Date:
2386                    sExpires = "; expires=" + vEnd.toUTCString() + "; max-age=34560000";
2387                    break;
2388            }
2389        }
2390        if(!sDomain)sDomain = "."+location.hostname;
2391        //console.log("SAVE COOKIE", sKey, sDomain);
2392
2393        // console.log("sExpires", sExpires)
2394
2395        document.cookie = encodeURIComponent(sKey) + "=" + encodeURIComponent(sValue) + sExpires + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "") + (bSecure ? "; secure" : "");
2396        return true;
2397    };
2398    Cookie.prototype.removeItem = function (sKey, sPath, sDomain) {
2399        if (!sKey || !this.hasItem(sKey)) {
2400            return false;
2401        }
2402        document.cookie = encodeURIComponent(sKey) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT" + (sDomain ? "; domain=" + sDomain : "") + (sPath ? "; path=" + sPath : "");
2403        return true;
2404    };
2405    Cookie.prototype.hasItem = function (sKey) {
2406        return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
2407    };
2408    Cookie.prototype.keys = function () {
2409        var aKeys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/);
2410        for (var nIdx = 0; nIdx < aKeys.length; nIdx++) {
2411            aKeys[nIdx] = decodeURIComponent(aKeys[nIdx]);
2412        }
2413        return aKeys;
2414    };
2415
2416    return Cookie;
2417})();
2418
2419/* ==================== vendor/15-local-storage.js ==================== */
2420;
2421/* File: Compat vendor - bg.ecard.LocalStorage */
2422/* ДОСЛОВНО (байт-за-байт) копие от: bg.ecard\main�g.ecard.LocalStorage.js. НЕ РЕДАКТИРАЙ. Самодостатъчен. */
2423/*# bg.ecard.LocalStorage  */
2424
2425bg.ecard.LocalStorage = function (prefix) {
2426    this.prefix = prefix;
2427}
2428
2429bg.ecard.LocalStorage.prototype.setItem = function (key, value) {
2430    if (localStorage && key != undefined && value != undefined) {
2431        localStorage.setItem(this.prefix + '-' + key, typeof value == 'object' ? JSON.stringify(value) : value);
2432        return true;
2433    }
2434    return false;
2435	
2436}
2437
2438bg.ecard.LocalStorage.prototype.getItem = function (key, defaultValue) {
2439    if (localStorage && key != undefined) {
2440        var value = localStorage.getItem(this.prefix + '-' + key);
2441        if (value != undefined) {
2442            try{ 
2443                return JSON.parse(value);
2444            }catch(e){
2445                return defaultValue != undefined ? defaultValue : null; 
2446            }            
2447        } else {
2448            return defaultValue != undefined ? defaultValue : null;
2449        }
2450    }
2451    return defaultValue;
2452}
2453
2454bg.ecard.LocalStorage.prototype.removeItem = function (key) {
2455    if (localStorage) {
2456        localStorage.removeItem(this.prefix + '-' + key);
2457    }
2458}
2459
2460
2461/* ==================== vendor/16-dragger.js ==================== */
2462;
2463/* File: Compat vendor - bg.ecard.Dragger */
2464/* ДОСЛОВНО (байт-за-байт) копие от: bg.ecard\main�g.ecard.Dragger.js. НЕ РЕДАКТИРАЙ.
2465 * Ползва bg.ecard.helpers.hasTouchScreen() (vendored) + TweenMax (external, на страницата). custom/7777. */
2466/*#  bg.ecard.Dragger */
2467bg.ecard.Dragger = (function () {
2468    var Dragger = function (holder, offset, isLogged) {
2469        this.holder = holder;
2470        this._offset = offset;
2471        this._isLogged = isLogged
2472
2473        this.resize(1);
2474
2475        this.rect = {
2476            top: 0,
2477            bottom: 0
2478        }
2479
2480        this._mousedown = mousedown.bind(this);
2481        this._mousemove = mousemove.bind(this);
2482        this._mouseup = mouseup.bind(this);
2483        this._touch = onTouch.bind(this);
2484
2485        let hasTouch = bg.ecard.helpers.hasTouchScreen();
2486        // console.log("hasTouch ==> ", hasTouch);
2487        if(hasTouch){
2488            this.holder.addEventListener("touchstart", this._mousedown);
2489            document.addEventListener("touchmove", this._mousemove);
2490            document.addEventListener("touchend", this._mouseup);
2491        } else {
2492            this.holder.addEventListener("mousedown", this._mousedown);
2493            document.addEventListener("mousemove", this._mousemove);
2494            document.addEventListener("mouseup", this._mouseup); 
2495        }
2496        // this.holder.addEventListener("touchstart", this._touch);
2497    }
2498
2499    function mousedown(e) {
2500        this._onDown = true;
2501        this.pageY = e.pageY || e.touches[0].pageY;
2502        e.preventDefault(); 
2503        e.stopPropagation();
2504    }
2505
2506    function onTouch(){
2507        this.onDrag(1, 1);
2508        TweenMax.to(this.holder,0.2,{x:0,y:this.offset});
2509        if(!this._isLogged){
2510            TweenMax.to(this.holder,0.4,{x:0,y:0}); 
2511        }
2512    }
2513
2514    function mousemove(e) {
2515        if (!this._onDown) return;
2516        var pageY = e.pageY || e.touches[0].pageY;
2517
2518        var currentOffset = Math.max(0, Math.min(this.offset, pageY - this.pageY));
2519        this.rate =  currentOffset / this.offset;
2520
2521        var r = 400/2;
2522        var rot = (30-(this.rate*60))*Math.PI/180;
2523        var dx = -r+28+Math.cos(rot)*r;      
2524        TweenMax.set(
2525            this.holder, {
2526                y: currentOffset,
2527                x: dx
2528            }
2529        );
2530
2531        this.speed = pageY - this.prevY;
2532        this.prevY = pageY;
2533    }
2534
2535    function mouseup(e) {
2536        if (!this._onDown) return;
2537        this._onDown = false;
2538
2539        if( this.rate > 0.7){            
2540            this.onDrag(this.rate, this.speed);
2541            TweenMax.to(this.holder,0.2,{x:0,y:this.offset});
2542        } else {
2543            TweenMax.to(this.holder,0.4,{x:0,y:0});        
2544        }
2545
2546        if(!this._isLogged){
2547            TweenMax.to(this.holder,0.4,{x:0,y:0}); 
2548        }
2549    }
2550
2551    function onRelease(){
2552        var r = 400/2;
2553        var rot = (30-(this.rate*60))*Math.PI/180;
2554        var dx = -r+28+Math.cos(rot)*r;        
2555
2556        TweenMax.set(
2557            this.holder, {
2558                top: currentOffset,
2559                x: dx
2560            }
2561        );
2562    }
2563
2564    Dragger.prototype.resize = function (rate) {
2565        this.offset = this.holder.parentNode.offsetHeight - (this._offset*rate);
2566    }
2567
2568    Dragger.prototype.onDrag = function (progress, speed) {
2569    }
2570
2571    Dragger.prototype.destroy = function () {
2572        this.holder.removeEventListener("mousedown", this._mousedown);
2573        document.removeEventListener("mousemove", this._mousemove);
2574        document.removeEventListener("mouseup", this._mouseup);
2575        this.holder.removeEventListener("touchstart", this._touch);
2576    }
2577
2578    return Dragger;
2579})();
2580
2581/* ==================== shim.js ==================== */
2582;
2583/* File: Compat - shim (bg.ecard.* runtime contract → window.Framework adapter layer) */
2584/**
2585 * Compat shim за bg.ecard.promo върху новия фреймуърк (app/).
2586 *
2587 * ОБХВАТ НА ТОЗИ ФАЙЛ = адаптерният/glue слой от PROMO-MIGRATION-ANALYSIS.md:
2588 *   00  namespace (не клобва server-inject)
2589 *   И3  bg.ecard.appConfig alias (ЕДИН обект = window.siteSettings = AppSettings.data)
2590 *   50  bg.ecard.app фасада (params / const / error / interface / network / navigation / events)
2591 *   И1  event bus адаптер (bind/unbind/unbindAll/trigger върху споделения App.event)
2592 *   И2  bg.ecard.app.network сокет фасада
2593 *   И5  bg.ecard.app.navigation.receveData passthrough
2594 *       app.interface (env/orientation/parser + windowResized/orientation:change notifier)
2595 *
2596 * НЕ Е ТУК (отделни стъпки от плана — виж по-долу; НЕ ги фабрикувай, копирай/портни от source):
2597 *   - vendor\ ДОСЛОВНИ копия: bg.ecard core (utils.extendClass, parseCurrency, plural,
2598 *     Number.prototype.formatCurrency), log, EventDispatcher (per-instance dispatcher-ите:
2599 *     `this.events = new bg.ecard.EventDispatcher(this)`), BaseElement/BaseManager/UIManager,
2600 *     timer, ui\UIElementClass, baseComponent, DomTarget(s), Helpers, Network.Ajax, UAParser,
2601 *     Condition, ModuleManager, LocalStorage, Cookie, CachedStorage, ViewPort, UIElementCaller.
2602 *   - И4 hydrator (CompatPage): порт на bg.ecard.WebsitePage.js initUIElements/DOMappend/
2603 *     DOMremove/DOMreinit + partition guard + DOM_ADDED re-scan. Зависи от vendored UIElementClass
2604 *     и UIManager (managersList), затова е след vendor слоя.
2605 * Причина за разделянето: изброените са ЛИТЕРАЛНИ копия / портове от конкретни стари файлове,
2606 * които планът маркира с „прочети преди имплементация". Този shim е само истинската glue логика.
2607 *
2608 * Ред на зареждане (index.html): framework.iife.js → ТОЗИ shim → components.manifest → app.iife.js.
2609 * framework.iife.js НЕ инстанцира App (прави го app.iife.js), затова тук всичко към App/App.event
2610 * е LAZY — резолвва се при първо извикване (след DOMContentLoaded, когато new App() е минал).
2611 */
2612(function (window, document) {
2613    "use strict";
2614
2615    var Framework = window.Framework;
2616    if (!Framework) {
2617        console.warn("[compat] window.Framework липсва — shim-ът е inert (зареди го СЛЕД framework.iife.js).");
2618        return;
2619    }
2620
2621    // ── 00. namespace (толерантно към server-inject: не презаписва съществуващи клонове) ──
2622    var bg = window.bg = window.bg || {};
2623    bg.ecard = bg.ecard || {};
2624    bg.ecard.campaigns = bg.ecard.campaigns || {};
2625    // Кампаниите пишат в bg.ecard.promo.* (config/класове), но никой не създава root-а —
2626    // старият bootstrap го е правил. Създаваме го (не клобва server-inject).
2627    bg.ecard.promo = bg.ecard.promo || {};
2628    // Стар bootstrap: custom/*/dev.js вика bg.ecard.start(...). No-op — умишлено НЕ стартира
2629    // стария свят (новият App вече е bootstrap-нат). Съответства на плана.
2630    if (typeof bg.ecard.start !== "function") bg.ecard.start = function () {};
2631    bg.ecard.__compat = true;
2632
2633    // ── И3. appConfig alias — ЗАДЪЛЖИТЕЛНО един и същ обект като AppSettings.data ──
2634    // App ctor прави AppSettings.init(window.siteSettings) → AppSettings.data === window.siteSettings.
2635    // Мутациите на CONSTANT_PARAMS.CUSTOMER_INFO от SocketManager минават през AppSettings.get(),
2636    // т.е. през същия обект → видими и за кампаниите през bg.ecard.appConfig.
2637    //
2638    // Докато backend-ът още инжектира bg.ecard.appConfig като ОТДЕЛЕН обект (успоредно с
2639    // window.siteSettings), голото `||` никога не алиасва — bg.ecard.appConfig си остава
2640    // завинаги различен обект и socket-driven мутациите (CUSTOMER_INFO и др.) не стигат до
2641    // кампаниите. Затова мерджваме: window.siteSettings/AppSettings.data печели за колизиращи
2642    // ключове (той е обектът, който SocketManager реално мутира), а ключове, налични само в
2643    // старото inline appConfig, се пренасят — и `bg.ecard.appConfig` се пренасочва към същия
2644    // обект, вместо да разчита на ||.
2645    (function () {
2646        var canonical = window.siteSettings || Framework.AppSettings.get() || {};
2647        if (bg.ecard.appConfig && bg.ecard.appConfig !== canonical) {
2648            for (var key in bg.ecard.appConfig) {
2649                if (Object.prototype.hasOwnProperty.call(bg.ecard.appConfig, key) && !(key in canonical)) {
2650                    canonical[key] = bg.ecard.appConfig[key];
2651                }
2652            }
2653        }
2654        bg.ecard.appConfig = canonical;
2655    })();
2656
2657    // Lazy достъп до споделения bus / SocketManager (App се инстанцира от app.iife.js по-късно).
2658    function bus() { return Framework.App && Framework.App.event; }
2659    function net() { return Framework.App && Framework.App.network; }
2660
2661    /* ───────────────────────────── И1. Event bus адаптер ─────────────────────────────
2662     * Стар договор (bg.ecard.EventDispatcher, инстанцията bg.ecard.app.events):
2663     *   bind(type, caller, action, execOnce);
2664     *   trigger(type, data, data2) → caller[action](data, data2, {caller, eventParams});
2665     *   unbind(type, caller, action); unbindAll(caller).
2666     * Дизайн: ЕДИН споделен bus = App.event. Всеки bind регистрира wrapper на App.event,
2667     * който възпроизвежда дословно стария Event.prototype.trigger (динамичен lookup на метода,
2668     * мета 3-ти аргумент, console.error формата, self-unbind при execOnce). Пазим собствен
2669     * регистър {eventType → [{caller, action, wrapper}]} за точни unbind/unbindAll
2670     * (новият EventDispatcher.off филтрира по context, не по caller).
2671     */
2672    var reg = Object.create(null); // eventType -> [{ caller, action, wrapper }]
2673
2674    function bind(eventType, caller, action, execOnce) {
2675        // Дословна репродукция на bg.ecard.EventDispatcher.Event.prototype.trigger:
2676        var wrapper = function (data, data2) {
2677            var fn = caller ? caller[action] : undefined;
2678            if (typeof fn === "function") {
2679                fn.call(caller, data, data2, { caller: caller, eventParam
2679s: { action: action, name: eventType } });
2680                if (execOnce) unbind(eventType, caller, action);
2681            } else {
2682                // Старият формат на грешката (caller.params.type когато го има).
2683                console.error({
2684                    errorId: "Event triger target action missing",
2685                    elementName: (caller && caller.params ? caller.params.type : caller) + " - action: " + action
2686                });
2687            }
2688        };
2689        (reg[eventType] || (reg[eventType] = [])).push({ caller: caller, action: action, wrapper: wrapper });
2690        var b = bus();
2691        if (b) b.on(eventType, wrapper, caller);
2692    }
2693
2694    function unbind(eventType, caller, action) {
2695        var list = reg[eventType];
2696        if (!list) return;
2697        var b = bus();
2698        for (var i = list.length - 1; i > -1; i--) {
2699            var e = list[i];
2700            if (e.caller === caller && e.action === action) {
2701                if (b) b.off(eventType, e.wrapper);
2702                list.splice(i, 1);
2703            }
2704        }
2705        if (!list.length) delete reg[eventType];
2706    }
2707
2708    function unbindAll(caller) {
2709        var b = bus();
2710        for (var eventType in reg) {
2711            var list = reg[eventType];
2712            for (var i = list.length - 1; i > -1; i--) {
2713                if (list[i].caller === caller) {
2714                    if (b) b.off(eventType, list[i].wrapper);
2715                    list.splice(i, 1);
2716                }
2717            }
2718            if (!list.length) delete reg[eventType];
2719        }
2720    }
2721
2722    function trigger(eventType, data, data2) {
2723        // Старият trigger dispatch-ва bridge:event за всяко не-timer събитие (P7 observability;
2724        // мостът в новия фреймуърк е изключен → няма двойна доставка).
2725        if (typeof eventType === "string" && eventType.indexOf("timer.") < 0) {
2726            try {
2727                window.dispatchEvent(new CustomEvent("bridge:event", {
2728                    detail: { event: eventType, data: data, data2: data2 }
2729                }));
2730            } catch (e) { /* CustomEvent недостъпен — без значение за доставката */ }
2731        }
2732        var b = bus();
2733        if (b) b.trigger(eventType, data, data2); // фира и старите wrapper-и, и новите listener-и
2734    }
2735
2736    var eventsAdapter = {
2737        bind: bind,
2738        unbind: unbind,
2739        unbindAll: unbindAll,
2740        trigger: trigger,
2741        // disable/enable → споделения статичен disabled-set на новия EventDispatcher.
2742        disable: function (type) { Framework.EventDispatcher.disable(type); },
2743        enable: function (type) { Framework.EventDispatcher.enable(type); }
2744        // inbind умишлено ЛИПСВА — и в стария свят беше TypeError (идентичен отказ).
2745    };
2746
2747    /* ───────────────────────── app.interface (env / orientation / parser) ─────────────────────────
2748     * Порт на bg.ecard.WebsiteUI.getResolution: env се избира по appConfig.envDeviceType
2749     * (НЕ по реалната резолюция). orientation + windowResized/orientation:change идват от
2750     * порт на bg.ecard.ResolutionManager (debounce = app.const.screenResizeNotifyTimeout,
2751     * first-resize skip запазен).
2752     */
2753    function computeEnv() {
2754        var envEl = [
2755            { environment: "desktop", id: "dt", element: document.querySelector("#env-desktop") },
2756            { environment: "mobile", id: "mbl", element: document.querySelector("#env-mobile") }
2757        ];
2758        var want = bg.ecard.appConfig && bg.ecard.appConfig.envDeviceType;
2759        for (var i = 0; i < envEl.length; i++) {
2760            if (envEl[i].environment === want) return envEl[i];
2761        }
2762        return envEl[0];
2763    }
2764
2765    function getOrientation() {
2766        switch (window.orientation) {
2767            case 0:
2768            case 180:
2769                return "portrait";
2770            case -90:
2771            case 90:
2772            default:
2773                return "landscape";
2774        }
2775    }
2776
2777    var iface = {
2778        env: computeEnv(),
2779        orientation: getOrientation(),
2780        // interface.parser се нуждае от РЕЗУЛТАТА на UAParser(), не от функцията. Старият
2781        // bg.ecard.UAParser() е `return UAParser()`, а Device.ua също е `UAParser()`
2782        // (device.js:34) → идентична форма. Затова Device.ua е ТОЧЕН еквивалент тук; викаме
2783        // vendored bg.ecard.UAParser() ако е наличен само за да е буквално същият source.
2784        get parser() {
2785            return (typeof bg.ecard.UAParser === "function")
2786                ? bg.ecard.UAParser()
2787                : (Framework.Device && Framework.Device.ua) || null;
2788        }
2789    };
2790
2791    /* ───────────────────────────── И2. app.network сокет фасада ─────────────────────────────
2792     * Единственият консуматор в promo (vendored UIElementClass.socketSend/onConnect):
2793     *   app.network.active.socket[name].state.active   → real.isOpen()
2794     *   app.network.active.socket[name].send(<стринг>)  → real.send(обект)  (новият Socket сам JSON-ва)
2795     * net.Socket.<name>.open тече по споделения bus (Socket.open го trigger-ва там).
2796     */
2797    function wrapSocket(real) {
2798        if (!real) return real;
2799        if (real.__compatWrap) return real.__compatWrap;
2800        var w = {
2801            _real: real,
2802            state: { get active() { return real.isOpen(); } },
2803            send: function (payload) {
2804                // Старият буфер пази ВЕЧЕ stringify-нати съобщения; новият Socket.send JSON-ва сам.
2805                return real.send(typeof payload === "string" ? JSON.parse(payload) : payload);
2806            }
2807        };
2808        Object.defineProperty(real, "__compatWrap", { value: w, enumerable: false });
2809        return w;
2810    }
2811
2812    var networkFacade = {
2813        active: {
2814            get socket() {
2815                var out = {};
2816                var mgr = net();
2817                var real = (mgr && mgr.active && mgr.active.socket) || {};
2818                for (var k in real) out[k] = wrapSocket(real[k]);
2819                return out;
2820            }
2821        }
2822    };
2823
2824    /* ───────────────────────────── И5. navigation passthrough ─────────────────────────────
2825     * Кампанийният AJAX е vendored bg.ecard.Network.Ajax (суров XHR) и вика receveData ръчно —
2826     * не минава през новия Ajax.onResponse hook, така че няма двойна обработка.
2827     */
2828    var navigationFacade = {
2829        receveData: function (data) { return Framework.NavigationManager.receveData(data); }
2830    };
2831
2832    /* ───────────────────────────── 50. bg.ecard.app фасада ───────────────────────────── */
2833    var app = bg.ecard.app = bg.ecard.app || {};
2834    app.params = app.params || {};
2835    if (app.params.debug === undefined) {
2836        app.params.debug = (bg.ecard.appConfig && bg.ecard.appConfig.debug) || false;
2837    }
2838    app.const = app.const || {};
2839    if (app.const.screenResizeNotifyTimeout === undefined) app.const.screenResizeNotifyTimeout = 200;
2840    if (typeof app.error !== "function") {
2841        app.error = function () { console.error.apply(console, arguments); };
2842    }
2843    app.interface = iface;
2844    app.network = networkFacade;
2845    app.navigation = navigationFacade;
2846    app.events = eventsAdapter;
2847
2848    /* ── mini-ResolutionManager порт: windowResized + orientation:change (след app.events/const) ── */
2849    var resizeCount = 0;
2850    var notifyTimeout = null;
2851    var lastOrientation;
2852
2853    function notifyForResize() {
2854        eventsAdapter.trigger("windowResized");
2855        if (lastOrientation !== iface.orientation) {
2856            eventsAdapter.trigger("orientation:change", iface.orientation);
2857            lastOrientation = iface.orientation;
2858        }
2859        notifyTimeout = null;
2860    }
2861
2862    function processWindowResize() {
2863        iface.orientation = getOrientation();
2864        if (resizeCount > 0) { // first-resize skip (старият ResolutionManager ctor)
2865            if (notifyTimeout) clearTimeout(notifyTimeout);
2866            notifyTimeout = setTimeout(notifyForResize, app.const.screenResizeNotifyTimeout);
2867        }
2868        resizeCount++;
2869    }
2870
2871    window.addEventListener("resize", processWindowResize);
2872    window.addEventListener("orientationchange", processWindowResize);
2873    processWindowResize(); // initial: сетва orientation, count 0→1, без notify
2874
2875})(window, document);
2876
2877
2878/* ==================== hydrator.js ==================== */
2879;
2880/* File: Compat - hydrator (CompatPage — порт на bg.ecard.WebsitePage хидратацията, И4) */
2881/**
2882 * И4 от PROMO-MIGRATION-ANALYSIS.md — legacy хидратор за bg.ecard.promo.
2883 *
2884 * ПОРТ (близък до дословен) на 4-те метода от bg.ecard\main\bg.ecard.WebsitePage.js:
2885 *   initUIElements / DOMappend / DOMremove / DOMreinit
2886 * ПЛЮС новите интеграционни добавки (единствените умишлени разлики спрямо оригинала):
2887 *   - Partition guard: типове, регистрирани и като НОВ компонент (ComponentsManager.check
2888 *     или в window.__COMPONENTS__), се пропускат с еднократен warn → без ДВОЙНА инстанциация.
2889 *   - DOMappend след legacy init вика Framework.DomManager.init(holder) (мигрирани компоненти
2890 *     в инжектиран от кампания HTML).
2891 *   - DOMremove вика и Framework.ComponentsManager.remove(holder) — пазено вътрешно от _hasAppend.
2892 *   - Абонамент за Events.DOM_ADDED ("dom:added") → re-хидратация на съдържание, сменено от
2893 *     новия NavigationManager.
2894 * Регистрите остават ДИЗЮНКТНИ: legacy маркер `data-has-init` vs нов `element._hasAppend`.
2895 *
2896 * НЕ Е ПОРТНАТО (page-loading пътища — новият NavigationManager ги прави): loadData/processData/
2897 * processCss/createHolder/checkForDOMholder/show/hide. Хидраторът работи само върху вече наличен DOM.
2898 *
2899 * PREREQUISITES (vendor слой, P2 — БЕЗ тях хидраторът е inert, не crash-ва):
2900 *   bg.ecard.UIManager      — this.ui (addManager/addElement/uiElements)
2901 *   bg.ecard.DomTargets     — сканиране на [data-element-type]
2902 *   bg.ecard.DomTarget       — (транзитивно, през DomTargets)
2903 *   + самите legacy класове bg.ecard[type] идват от кампанийните бандъли.
2904 * PREREQUISITE (shim.js): bg.ecard.app.events адаптерът (bus wiring минава през него).
2905 *
2906 * Ред на зареждане: framework.iife.js → shim.js → ТОЗИ файл → components.manifest → app.iife.js.
2907 */
2908(function (window, document) {
2909    "use strict";
2910
2911    var Framework = window.Framework;
2912    if (!Framework) {
2913        console.warn("[compat/hydrator] window.Framework липсва — inert (зареди СЛЕД framework.iife.js).");
2914        return;
2915    }
2916
2917    var bg = window.bg = window.bg || {};
2918    bg.ecard = bg.ecard || {};
2919
2920    // ── Partition guard: дали типът е вече НОВ компонент (за да не го инстанцираме и legacy) ──
2921    var _dirtyWarned = Object.create(null);
2922
2923    function isNewComponentType(type) {
2924        try {
2925            if (Framework.ComponentsManager && Framework.ComponentsManager.check(type)) return true;
2926        } catch (e) { /* check хвърля само при non-string — legacy типовете са стрингове */ }
2927        var manifest = window.__COMPONENTS__ || {};
2928        return (type in manifest) || (type.toLowerCase() in manifest);
2929    }
2930
2931    function warnDirty(type) {
2932        if (_dirtyWarned[type]) return;
2933        _dirtyWarned[type] = true;
2934        // console.warn("[compat] dirty type: " + type +
2935        //     " — регистриран и като нов компонент; пропуснат от legacy hydrator (двойна инстанциация избегната).");
2936    }
2937
2938    /* ───────────────────────────────── CompatPage ───────────────────────────────── */
2939    function CompatPage() {
2940        // UIManager чете parent.params.id (в оригинала WebsitePage инстанциите го получаваха от
2941        // WebsitePagesManager). Тук е фиксиран — единственият CompatPage за страницата.
2942        this.params = { id: "compat", type: "CompatPage" };
2943        this.indexCount = 0;
2944        this.ui = new bg.ecard.UIManager(this); // vendored UIManager (addManager/addElement/uiElements)
2945
2946        // Bus wiring през shim адаптера (1:1 с оригиналния initClassWebsitePage) — минава по
2947        // споделения App.event, така че стар trigger("dom:append"/…) стига дотук.
2948        var ev = bg.ecard.app && bg.ecard.app.events;
2949        if (ev) {
2950            ev.bind("dom:append", this, "DOMappend");
2951            ev.bind("dom:remove", this, "DOMremove");
2952            ev.bind("dom:reinit", this, "DOMreinit");
2953            // Нова добавка: съдържание сменено от новия NavigationManager → re-хидратирай legacy.
2954            ev.bind("dom:added", this, "DOMadded");
2955        } else {
2956            console.warn("[compat/hydrator] bg.ecard.app.events липсва (зареди shim.js преди hydrator.js) — bus wiring прескочен.");
2957        }
2958    }
2959
2960    // Порт: DOMreinit (WebsitePage.js:47-50)
2961    CompatPage.prototype.DOMreinit = function (data) {
2962        this.DOMremove(data.holder);
2963        this.DOMappend(data);
2964    };
2965
2966    // Нова добавка: DOM_ADDED payload е holder-ът (dom-manager.js:81).
2967    CompatPage.prototype.DOMadded = function (holder) {
2968        if (holder && holder.nodeType === 1) this.initUIElements(holder);
2969    };
2970
2971    // Порт: DOMappend (WebsitePage.js:52-175) + Framework.DomManager.init след legacy init.
2972    CompatPage.prototype.DOMappend = function (data) {
2973        var self = this;
2974
2975        var scriptTags = data.holder.getElementsByTagName("script");
2976        for (var i = 0; i < scriptTags.length; i++) {
2977            // 1:1 с оригинала — кампанийният AJAX HTML носи inline скриптове, които трябва да се изпълнят.
2978            // eslint-disable-next-line no-eval
2979            eval(scriptTags[i].innerHTML);
2980        }
2981
2982        var jsFilesArray = window.__APP_CONFIG__ &&
2983            window.__APP_CONFIG__.dynamicConfig &&
2984            window.__APP_CONFIG__.dynamicConfig.chunkFilesToLoad &&
2985            window.__APP_CONFIG__.dynamicConfig.chunkFilesToLoad.js;
2986
2987        if (jsFilesArray) {
2988            try {
2989                loadScriptsParallel(jsFilesArray, initContent);
2990            } catch (error) {
2991                console.log(error);
2992            }
2993        } else {
2994            initContent();
2995        }
2996
2997        function initContent() {
2998            self.initUIElements(data.holder, data.forceInit, data.skipReinit);
2999
3000            // Нова добавка: инициализирай МИГРИРАНИТЕ компоненти в инжектирания HTML.
3001            if (Framework.DomManager) Framework.DomManager.init(data.holder);
3002
3003            if (data.newHtml) {
3004                var animationManager = data.holder.dataset.animationManager != undefined
3005                    ? [data.holder]
3006                    : data.holder.querySelectorAll("[data-animation-manager]");
3007                for (var i = 0; i < animationManager.length; i++) {
3008                    var holder = animationManager[i];
3009                    bg.ecard.app.events.trigger("animation:start", {
3010                        type: holder.dataset.animationType,
3011                        elements: holder.querySelectorAll(holder.dataset.animationElements),
3012                        params: { count: 30 }
3013                    });
3014                }
3015            }
3016
3017            setTimeout(function () { bg.ecard.app.events.trigger("dom:ready", data.holder); }, 2);
3018        }
3019
3020        function loadScriptsParallel(filesToLoadArray, callback) {
3021            var hasLocalHost = false;
3022            var params = new URLSearchParams(window.location.search);
3023            if (params.get("localhost") === "1") hasLocalHost = true;
3024
3025            if (!filesToLoadArray || !filesToLoadArray.length) {
3026                callback();
3027                return;
3028            }
3029
3030            var scripts = filesToLoadArray;
3031            var loadedCount = 0;
3032            var hasError = false;
3033
3034            function onComplete() {
3035                loadedCount++;
3036                if (loadedCount === scripts.length && !hasError) callback();
3037            }
3038            function onError(src) {
3039                if (hasError) return;
3040                hasError = true;
3041                console.error("Failed to load script:", src);
3042            }
3043
3044            for (var i = 0; i < scripts.length; i++) {
3045                var scriptSrc;
3046                if (hasLocalHost) {
3047                    var version = Date.now();
3048                    scriptSrc = scripts[i].devUrl + "?v=" + version;
3049                } else {
3050                    scriptSrc = scripts[i].prodUrl;
3051                }
3052
3053                (function (src) {
3054                    if (isScriptAlreadyAdded(src)) { onComplete(); return; }
3055                    var script = document.createElement("script");
3056                    script.type = "text/javascript";
3057                    script.src = src;
3058                    script.async = true;
3059                    script.onload = function () { onComplete(); };
3060                    script.onerror = function () { onError(src); };
3061                    document.head.appendChild(script);
3062                })(scriptSrc);
3063            }
3064
3065            function isScriptAlreadyAdded(newSrc) {
3066                var existing = document.getElementsByTagName("script");
3067                for (var i = 0; i < existing.length; i++) {
3068                    if (existing[i].src.split("?")[0] === newSrc.split("?")[0]) return true;
3069                }
3070                return false;
3071            }
3072        }
3073    };
3074
3075    // Порт: DOMremove (WebsitePage.js:177-211) + Framework.ComponentsManager.remove (нови компоненти).
3076    CompatPage.prototype.DOMremove = function (holder, params) {
3077        var elements = holder.querySelectorAll("[data-has-init]");
3078        for (var i = elements.length - 1; i > -1; i--) {
3079            if (elements[i] && elements[i].hasAttribute("data-skip-reinit") && params && params.skipReinit) continue;
3080            var index = parseInt(elements[i].dataset.hasInit);
3081            if (index in this.ui.uiElements) {
3082                var comp = this.ui.uiElements[index];
3083                try {
3084                    comp.onDestroy();
3085                } catch (e) { /* оригиналът също гълташе грешката тук */ }
3086                // NB: оригиналът прави `delete comp[index]` (изтрива несъществуващо property на
3087                // компонента, НЕ от this.ui.uiElements). Пазено 1:1 — поведението към Ð
3087ºÐ°Ð¼Ð¿Ð°Ð½Ð¸Ð¸Ñ‚е
3088                // (onDestroy + махане на data-has-init) е идентично; P7 diff-ът е детекторът.
3089                delete comp[index];
3090                elements[i].removeAttribute("data-has-init");
3091            }
3092        }
3093
3094        // Нова добавка: деинит на МИГРИРАНИТЕ компоненти (пази се вътрешно по _hasAppend →
3095        // дизюнктно с legacy data-has-init горе).
3096        if (Framework.ComponentsManager) Framework.ComponentsManager.remove(holder);
3097    };
3098
3099    // Порт: initUIElements (WebsitePage.js:408-486) + partition guard.
3100    CompatPage.prototype.initUIElements = function (holder, forceInit, skipReinit) {
3101        initManager.call(this, [holder]);
3102
3103        function initManager(list) {
3104            for (var i = 0; i < list.length; i++) {
3105                var el = list[i];
3106                if (el.dataset.hasInit != undefined || !el.dataset.manager) continue;
3107                var type = el.getAttribute("data-manager");
3108
3109                if (isNewComponentType(type)) { warnDirty(type); continue; } // guard
3110
3111                if (bg.ecard[type]) {
3112                    el.dataset.hasInit = this.indexCount++;
3113                    this.ui.addManager(new bg.ecard[type](this, { domEl: el }), el.dataset.managerId);
3114                }
3115            }
3116        }
3117
3118        var elements = new bg.ecard.DomTargets({ parentEl: holder, query: "[data-element-type]" });
3119        var l1 = elements.targets.length;
3120        for (var i = 0; i < l1; i++) {
3121            var element = elements.targetDOMs[i];
3122            var type = element.getAttribute("data-element-type");
3123            if (type == "WebsitePage") continue;
3124            var typeIndex = type.indexOf(".");
3125
3126            if (element.target.dataset.hasInit) continue;
3127
3128            if (element.target && element.target.dataset.hasInit && element.target.hasAttribute("data-skip-reinit") && skipReinit) continue;
3129            if (element.target.dataset.skipInit != undefined && !forceInit) continue;
3130
3131            if (isNewComponentType(type)) { warnDirty(type); continue; } // guard
3132
3133            if (typeIndex == -1) {
3134                if (bg.ecard[type]) {
3135                    try {
3136                        element.target.dataset.hasInit = this.indexCount++;
3137                        this.ui.addElement(new bg.ecard[type](this, { domEl: element }), element.target.dataset.hasInit);
3138                    } catch (e) {
3139                        console.warn(e);
3140                    }
3141                }
3142            } else {
3143                var cls = type.split(".");
3144                var obj = bg.ecard[cls[0]];
3145                for (var a = 1; a < cls.length; a++) {
3146                    obj = obj ? obj[cls[a]] : undefined;
3147                    if (!obj) break;
3148                }
3149                if (obj) {
3150                    element.target.dataset.hasInit = this.indexCount++;
3151                    this.ui.addElement(new obj(this, { domEl: element }), element.target.dataset.hasInit);
3152                }
3153            }
3154
3155            // init casino natlot games (порт 1:1)
3156            if (type === "casinoNatlotGame") {
3157                var gameObjName = element.getAttribute("data-game-obj-name");
3158                if (window.bg && window.bg.gamesEcard && window.bg.gamesEcard[gameObjName]) {
3159                    window.bg.gamesEcard[gameObjName].start();
3160                }
3161            }
3162        }
3163    };
3164
3165    /* ───────────────────────────────── boot ───────────────────────────────── */
3166    function hasPrerequisites() {
3167        var missing = [];
3168        if (typeof bg.ecard.UIManager !== "function") missing.push("bg.ecard.UIManager");
3169        if (typeof bg.ecard.DomTargets !== "function") missing.push("bg.ecard.DomTargets");
3170        if (missing.length) {
3171            console.warn("[compat/hydrator] липсва vendor слой: " + missing.join(", ") +
3172                " — CompatPage НЕ е стартиран (зареди vendored класовете преди hydrator.js).");
3173            return false;
3174        }
3175        return true;
3176    }
3177
3178    function boot() {
3179        if (bg.ecard.compatPage) return;             // идемпотентно
3180        if (!hasPrerequisites()) return;
3181        var page = bg.ecard.compatPage = new CompatPage();
3182        page.initUIElements(document.body);          // класическите синхронни кампанийни скриптове са изпълнени
3183    }
3184
3185    // Изложи класа за тестове/ръчна употреба.
3186    bg.ecard.CompatPage = CompatPage;
3187
3188    // "loading" е грешен праг за defer скрипт: defer винаги изпълнява СЛЕД парсване
3189    // (readyState вече "interactive"), т.е. клонът по-долу винаги щеше да вика boot()
3190    // веднага — преди campaigns бъндълите (следващите defer <script> тагове) да са
3191    // се изпълнили, докато bg.ecard.<CampaignClass> още не съществува. "complete" е
3192    // единственото readyState, при което DOMContentLoaded гарантирано вече е отминало.
3193    if (document.readyState === "complete") {
3194        boot();
3195    } else {
3196        document.addEventListener("DOMContentLoaded", boot);
3197    }
3198
3199})(window, document);

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.