mirror of
				https://gitlab.com/octospacc/octospacc.gitlab.io
				synced 2025-06-05 21:59:15 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			2729 lines
		
	
	
		
			92 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			2729 lines
		
	
	
		
			92 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| // http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 | |
| // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
 | |
| 
 | |
| // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
 | |
| 
 | |
| // MIT license
 | |
| 
 | |
| (function() {
 | |
|     var lastTime = 0;
 | |
|     var vendors = ['ms', 'moz', 'webkit', 'o'];
 | |
|     for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
 | |
|         window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
 | |
|         window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
 | |
|                                    || window[vendors[x]+'CancelRequestAnimationFrame'];
 | |
|     }
 | |
| 
 | |
|     if (!window.requestAnimationFrame)
 | |
|         window.requestAnimationFrame = function(callback, element) {
 | |
|             var currTime = new Date().getTime();
 | |
|             var timeToCall = Math.max(0, 16 - (currTime - lastTime));
 | |
|             var id = window.setTimeout(function() { callback(currTime + timeToCall); },
 | |
|               timeToCall);
 | |
|             lastTime = currTime + timeToCall;
 | |
|             return id;
 | |
|         };
 | |
| 
 | |
|     if (!window.cancelAnimationFrame)
 | |
|         window.cancelAnimationFrame = function(id) {
 | |
|             clearTimeout(id);
 | |
|         };
 | |
| }());
 | |
| 
 | |
| 
 | |
| 
 | |
| /*! npm.im/iphone-inline-video 2.0.2 */
 | |
| 
 | |
| var enableInlineVideo=function(){"use strict";/*! npm.im/intervalometer */
 | |
| function e(e,i,n,r){function t(n){d=i(t,r),e(n-(a||n)),a=n}var d,a;return{start:function(){d||t(0)},stop:function(){n(d),d=null,a=0}}}function i(i){return e(i,requestAnimationFrame,cancelAnimationFrame)}function n(e,i,n,r){function t(i){Boolean(e[n])===Boolean(r)&&i.stopImmediatePropagation(),delete e[n]}return e.addEventListener(i,t,!1),t}function r(e,i,n,r){function t(){return n[i]}function d(e){n[i]=e}r&&d(e[i]),Object.defineProperty(e,i,{get:t,set:d})}function t(e,i,n){n.addEventListener(i,function(){return e.dispatchEvent(new Event(i))})}function d(e,i){Promise.resolve().then(function(){e.dispatchEvent(new Event(i))})}function a(e){var i=new Audio;return t(e,"play",i),t(e,"playing",i),t(e,"pause",i),i.crossOrigin=e.crossOrigin,i.src=e.src||e.currentSrc||"data:",i}function o(e,i,n){(m||0)+200<Date.now()&&(e[b]=!0,m=Date.now()),n||(e.currentTime=i),w[++T%3]=100*i|0}function u(e){return e.driver.currentTime>=e.video.duration}function s(e){var i=this;i.video.readyState>=i.video.HAVE_FUTURE_DATA?(i.hasAudio||(i.driver.currentTime=i.video.currentTime+e*i.video.playbackRate/1e3,i.video.loop&&u(i)&&(i.driver.currentTime=0)),o(i.video,i.driver.currentTime)):i.video.networkState===i.video.NETWORK_IDLE&&0===i.video.buffered.length&&i.video.load(),i.video.ended&&(delete i.video[b],i.video.pause(!0))}function c(){var e=this,i=e[h];return e.webkitDisplayingFullscreen?void e[g]():("data:"!==i.driver.src&&i.driver.src!==e.src&&(o(e,0,!0),i.driver.src=e.src),void(e.paused&&(i.paused=!1,0===e.buffered.length&&e.load(),i.driver.play(),i.updater.start(),i.hasAudio||(d(e,"play"),i.video.readyState>=i.video.HAVE_ENOUGH_DATA&&d(e,"playing")))))}function v(e){var i=this,n=i[h];n.driver.pause(),n.updater.stop(),i.webkitDisplayingFullscreen&&i[E](),n.paused&&!e||(n.paused=!0,n.hasAudio||d(i,"pause"),i.ended&&(i[b]=!0,d(i,"ended")))}function p(e,n){var r=e[h]={};r.paused=!0,r.hasAudio=n,r.video=e,r.updater=i(s.bind(r)),n?r.driver=a(e):(e.addEventListener("canplay",function(){e.paused||d(e,"playing")}),r.driver={src:e.src||e.currentSrc||"data:",muted:!0,paused:!0,pause:function(){r.driver.paused=!0},play:function(){r.driver.paused=!1,u(r)&&o(e,0)},get ended(){return u(r)}}),e.addEventListener("emptied",function(){var i=!r.driver.src||"data:"===r.driver.src;r.driver.src&&r.driver.src!==e.src&&(o(e,0,!0),r.driver.src=e.src,i?r.driver.play():r.updater.stop())},!1),e.addEventListener("webkitbeginfullscreen",function(){e.paused?n&&0===r.driver.buffered.length&&r.driver.load():(e.pause(),e[g]())}),n&&(e.addEventListener("webkitendfullscreen",function(){r.driver.currentTime=e.currentTime}),e.addEventListener("seeking",function(){w.indexOf(100*e.currentTime|0)<0&&(r.driver.currentTime=e.currentTime)}))}function l(e){var i=e[h];e[g]=e.play,e[E]=e.pause,e.play=c,e.pause=v,r(e,"paused",i.driver),r(e,"muted",i.driver,!0),r(e,"playbackRate",i.driver,!0),r(e,"ended",i.driver),r(e,"loop",i.driver,!0),n(e,"seeking"),n(e,"seeked"),n(e,"timeupdate",b,!1),n(e,"ended",b,!1)}function f(e,i){if(void 0===i&&(i={}),!e[h]){if(!i.everywhere){if(!y)return;if(!(i.iPad||i.ipad?/iPhone|iPod|iPad/:/iPhone|iPod/).test(navigator.userAgent))return}!e.paused&&e.webkitDisplayingFullscreen&&e.pause(),p(e,!e.muted),l(e),e.classList.add("IIV"),e.muted&&e.autoplay&&e.play(),/iPhone|iPod|iPad/.test(navigator.platform)||console.warn("iphone-inline-video is not guaranteed to work in emulated environments")}}var m,y="object"==typeof document&&"object-fit"in document.head.style&&!matchMedia("(-webkit-video-playable-inline)").matches,h="bfred-it:iphone-inline-video",b="bfred-it:iphone-inline-video:event",g="bfred-it:iphone-inline-video:nativeplay",E="bfred-it:iphone-inline-video:nativepause",w=[],T=0;return f}();
 | |
| 
 | |
| if (!Array.isArray) {
 | |
|   Array.isArray = function(arg) {
 | |
|     return Object.prototype.toString.call(arg) === '[object Array]';
 | |
|   };
 | |
| }
 | |
| 
 | |
| (!this.CustomEvent || typeof this.CustomEvent === "object") && (function() {
 | |
|   this.CustomEvent = function CustomEvent(type, eventInitDict) {
 | |
|     var event;
 | |
|     eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: undefined};
 | |
| 
 | |
|     try {
 | |
|       event = document.createEvent('CustomEvent');
 | |
|       event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable, eventInitDict.detail);
 | |
|     } catch (error) {
 | |
|       event = document.createEvent('Event');
 | |
|       event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable);
 | |
|       event.detail = eventInitDict.detail;
 | |
|     }
 | |
| 
 | |
|     return event;
 | |
|   };
 | |
| })();
 | |
| 
 | |
| var Keys = {
 | |
|   BACKSPACE: 8,
 | |
|   ESC: 27,
 | |
|   TAB: 9,
 | |
|   RETURN: 13,
 | |
|   LEFT: 37,
 | |
|   UP: 38,
 | |
|   RIGHT: 39,
 | |
|   DOWN: 40
 | |
| };
 | |
| 
 | |
| var TWidget = {
 | |
|   options: {},
 | |
|   isFocused: false
 | |
| };
 | |
| function inFrame() {
 | |
|   return (window.parent != null && window != window.parent);
 | |
| }
 | |
| function inFullFrame() {
 | |
|   return inFrame() && TWidget.options.auto_height;
 | |
| }
 | |
| function isFocused() {
 | |
|   return inFrame() ? TWidget.isFocused : document.hasFocus();
 | |
| }
 | |
| 
 | |
| function l(lang_key, params, def_value) {
 | |
|   if (typeof params === 'string') {
 | |
|     def_value = params;
 | |
|     params = {};
 | |
|   }
 | |
|   params = params || {};
 | |
|   var value = l._keys[lang_key] || def_value || lang_key;
 | |
|   value = value.replace(/\{\{([A-Za-z_\-\d]{1,32}):(.+?)\}\}/g, function(lang_value, token, options) {
 | |
|     var number = +params[token] || 0;
 | |
|     var numeric_options = options.split('|');
 | |
|     var i;
 | |
|     if (number == 1) i = 0;
 | |
|     else i = 1;
 | |
|     if (typeof numeric_options[i] === 'undefined') {
 | |
|       i = 1;
 | |
|     }
 | |
|     var numeric_option = numeric_options[i] || '#';
 | |
|     return numeric_option.replace(/#/g, number);
 | |
|   });
 | |
|   value = value.replace(/\{([A-Za-z_\-\d]{1,32}):(.{1,256}?)\}/g, function(lang_value, token, options) {
 | |
|     var number = +params[token] || 0;
 | |
|     var numeric_options = options.split('|');
 | |
|     var i;
 | |
|     if (!number) i = 0;
 | |
|     else if (number == 1) i = 1;
 | |
|     else i = 2;
 | |
|     if (typeof numeric_options[i] === 'undefined') {
 | |
|       i = 0;
 | |
|     }
 | |
|     var numeric_option = numeric_options[i] || '#';
 | |
|     return numeric_option.replace(/#/g, number);
 | |
|   });
 | |
|   for (var param in params) {
 | |
|     value = value.split('{' + param + '}').join(params[param]);
 | |
|   }
 | |
|   return value;
 | |
| }
 | |
| l._keys = {};
 | |
| l.add = function(lang_values) {
 | |
|   for (var lang_key in lang_values) {
 | |
|     l._keys[lang_key] = lang_values[lang_key];
 | |
|   }
 | |
| }
 | |
| 
 | |
| var PostMessage = {
 | |
|   _callbacks: {},
 | |
|   _lastId: 0,
 | |
|   send: function(data, origin, callback) {
 | |
|     if (typeof origin === 'function') {
 | |
|       callback = origin; origin = null;
 | |
|     }
 | |
|     try {
 | |
|       if (callback) {
 | |
|         data._cb = ++PostMessage._lastId;
 | |
|         PostMessage._callbacks[data._cb] = callback;
 | |
|       }
 | |
|       window.parent.postMessage(JSON.stringify(data), origin || '*');
 | |
|     } catch(e) {
 | |
|       if (origin) alert('Bot domain invalid');
 | |
|     }
 | |
|   },
 | |
|   onMessage: function(event) {
 | |
|     if (event.source !== window.parent) return;
 | |
|     try {
 | |
|       var data = JSON.parse(event.data);
 | |
|     } catch(e) {
 | |
|       var data = {};
 | |
|     }
 | |
|     if (data.event == 'visible') {
 | |
|       if (!frameWasVisible) {
 | |
|         frameWasVisible = true;
 | |
|         TWidget.options.onVisible && TWidget.options.onVisible();
 | |
|       }
 | |
|       PostMessage.send({event: 'visible_off'});
 | |
|     }
 | |
|     else if (data.event == 'focus') {
 | |
|       TWidget.isFocused = data.has_focus;
 | |
|       triggerEvent(window, 'tg:focuschange');
 | |
|     }
 | |
|     else if (data.event == 'set_options') {
 | |
|       triggerEvent(window, 'tg:optionschange', {detail: data.options});
 | |
|     }
 | |
|     else if (data.event == 'get_info') {
 | |
|       triggerEvent(window, 'tg:inforequest', {detail: {
 | |
|         callback: function(value) {
 | |
|           PostMessage.send({event: 'callback', _cb: data._cb, value: value});
 | |
|         }
 | |
|       }});
 | |
|     }
 | |
|     else if (data.event == 'visible') {
 | |
|       if (!frameWasVisible) {
 | |
|         frameWasVisible = true;
 | |
|         TWidget.options.onVisible && TWidget.options.onVisible();
 | |
|       }
 | |
|       PostMessage.send({event: 'visible_off'});
 | |
|     }
 | |
|     else if (data.event == 'callback') {
 | |
|       if (PostMessage._callbacks[data._cb]) {
 | |
|         PostMessage._callbacks[data._cb](data.value);
 | |
|         delete PostMessage._callbacks[data._cb];
 | |
|       } else {
 | |
|         console.warn('Callback #' + data._cb + ' not found');
 | |
|       }
 | |
|     }
 | |
|     else {
 | |
|       triggerEvent(window, 'tg:postmessage', {detail: data});
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| var TPopups = {
 | |
|   _list: [],
 | |
|   _lastId: 1000000,
 | |
|   _inited: false,
 | |
|   init: function() {
 | |
|     if (!TPopups._inited) {
 | |
|       TPopups._inited = true;
 | |
|       if (window.Popups) {
 | |
|         TPopups._list = window.Popups; // legacy
 | |
|       }
 | |
|       addEvent(document, 'keydown', function(e) {
 | |
|         if (e.keyCode == Keys.ESC && TPopups._list.length > 0) {
 | |
|           e.stopImmediatePropagation();
 | |
|           e.preventDefault();
 | |
|           TPopups.close();
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|   },
 | |
|   open: function(popup_el, options) {
 | |
|     TPopups.init();
 | |
|     popup_el = ge1(popup_el);
 | |
|     if (!popup_el) {
 | |
|       return popup_el;
 | |
|     }
 | |
|     options = options || {};
 | |
|     var popup_id = popup_el.__puid;
 | |
|     if (!popup_id) {
 | |
|       popup_id = ++TPopups._lastId;
 | |
|       popup_el.__puid = popup_id;
 | |
|     }
 | |
|     popup_el.__options = options;
 | |
|     var index = TPopups._list.indexOf(popup_id);
 | |
|     if (index >= 0) {
 | |
|       TPopups._list.splice(index, 1);
 | |
|     }
 | |
|     TPopups._list.push(popup_id);
 | |
|     document.body.style.overflow = 'hidden';
 | |
|     document.body.appendChild(popup_el);
 | |
|     removeClass(popup_el, 'hide');
 | |
|     TPopups.setPosition(popup_el);
 | |
|     if (document.activeElement) {
 | |
|       document.activeElement.blur();
 | |
|     }
 | |
|     if (ge1('.js-popup_box', popup_el)) {
 | |
|       addEvent(popup_el, 'click', function(e) {
 | |
|         if (elInBody(e.target) &&
 | |
|             !hasClass(e.target, 'js-popup_box') &&
 | |
|             !gpeByClass(e.target, 'js-popup_box')) {
 | |
|           TPopups.close(popup_el);
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     gec('.js-popup_close', function() {
 | |
|       addEvent(this, 'click', function() {
 | |
|         TPopups.close(popup_el);
 | |
|       });
 | |
|     }, popup_el);
 | |
|     triggerEvent(popup_el, 'tg:popupopen');
 | |
|     return popup_el;
 | |
|   },
 | |
|   close: function(popup_el) {
 | |
|     if (!TPopups._list.length) return false;
 | |
|     var popup_id;
 | |
|     if (popup_el) {
 | |
|       popup_id = popup_el.__puid;
 | |
|     } else {
 | |
|       popup_id = TPopups._list.pop();
 | |
|       gec('.js-popup_container', function() {
 | |
|         if (popup_id == this.__puid) {
 | |
|           popup_el = this;
 | |
|           return false;
 | |
|         }
 | |
|       });
 | |
|     }
 | |
|     if (!popup_el) {
 | |
|       return false;
 | |
|     }
 | |
|     var options = popup_el.__options;
 | |
|     var index = TPopups._list.indexOf(popup_id);
 | |
|     if (index >= 0) {
 | |
|       TPopups._list.splice(index, 1);
 | |
|     }
 | |
|     if (!TPopups._list.length) {
 | |
|       document.body.style.overflow = '';
 | |
|     }
 | |
|     removeEvent(popup_el, 'click');
 | |
|     gec('.js-popup_close', function() {
 | |
|       removeEvent(this, 'click');
 | |
|     }, popup_el);
 | |
|     addClass(popup_el, 'hide');
 | |
|     triggerEvent(popup_el, 'tg:popupclose');
 | |
|   },
 | |
|   closeAll: function() {
 | |
|     while (TPopups._list.length) {
 | |
|       TPopups.close();
 | |
|     }
 | |
|   },
 | |
|   setPosition: function(popul_el) {
 | |
|     var popup_box = ge1('.js-popup_box', popul_el);
 | |
|     if (!popup_box) return;
 | |
|     getCoords(function(coords) {
 | |
|       var style      = window.getComputedStyle(popul_el);
 | |
|       var contTop    = parseInt(style.paddingTop);
 | |
|       var contBottom = parseInt(style.paddingBottom);
 | |
|       var marginMax  = popul_el.offsetHeight - contTop - contBottom - coords.elHeight;
 | |
|       var frameTop   = coords.frameTop || 0;
 | |
|       var deltaY     = (coords.clientHeight - coords.elHeight) / 2;
 | |
|       var marginTop  = deltaY - contTop - frameTop;
 | |
|       marginTop = Math.max(0, Math.min(marginMax, marginTop));
 | |
|       popup_box.style.marginTop = marginTop + 'px';
 | |
|     }, popup_box);
 | |
|   },
 | |
|   show: function(html, buttons, options) {
 | |
|     options = options || {};
 | |
|     var popup_el = newEl('div', 'tgme_popup_container js-popup_container tgme_popup_alert hide', '<div class="tgme_popup js-popup_box"><div class="tgme_popup_body"><div class="tgme_popup_text js-popup_text"></div><div class="tgme_popup_buttons js-popup_buttons"></div></div></div>');
 | |
|     var text_el = ge1('.js-popup_text', popup_el);
 | |
|     var buttons_el = ge1('.js-popup_buttons', popup_el);
 | |
|     setHtml(text_el, html);
 | |
|     var enterBtn = null, onEnterPress = null;
 | |
|     for (var i = 0; i < buttons.length; i++) {
 | |
|       var btn = buttons[i];
 | |
|       var button_el = newEl('div', 'tgme_popup_button' + (btn.close ? ' js-popup_close' : ''), btn.label);
 | |
|       btn.el = button_el;
 | |
|       buttons_el.appendChild(button_el);
 | |
|       if (btn.enter) {
 | |
|         enterBtn = button_el;
 | |
|       }
 | |
|       if (btn.onPress) {
 | |
|         addEvent(button_el, 'click', btn.onPress);
 | |
|       }
 | |
|     }
 | |
|     if (enterBtn) {
 | |
|       onEnterPress = function(e) {
 | |
|         if (e.keyCode == Keys.RETURN) {
 | |
|           e.stopImmediatePropagation();
 | |
|           e.preventDefault();
 | |
|           triggerEvent(enterBtn, 'click');
 | |
|         }
 | |
|       };
 | |
|       addEvent(document, 'keydown', onEnterPress);
 | |
|     }
 | |
|     var onPopupClose = function(e) {
 | |
|       if (enterBtn && onEnterPress) {
 | |
|         removeEvent(document, 'keydown', onEnterPress);
 | |
|       }
 | |
|       for (var i = 0; i < buttons.length; i++) {
 | |
|         var btn = buttons[i];
 | |
|         if (btn.onPress) {
 | |
|           removeEvent(btn.el, 'click', btn.onPress);
 | |
|         }
 | |
|       }
 | |
|       removeEvent(popup_el, 'tg:popupclose', onPopupClose);
 | |
|       removeEl(popup_el);
 | |
|     };
 | |
|     addEvent(popup_el, 'tg:popupclose', onPopupClose);
 | |
|     return TPopups.open(popup_el);
 | |
|   }
 | |
| };
 | |
| 
 | |
| function showAlert(html, onClose) {
 | |
|   return TPopups.show(html, [{
 | |
|     label: l('WEB_CLOSE', 'Close'),
 | |
|     enter: true,
 | |
|     close: true
 | |
|   }]);
 | |
| }
 | |
| 
 | |
| function showConfirm(html, onConfirm, confirm_btn, onCancel, cancel_btn) {
 | |
|   var popup_el = TPopups.show(html, [{
 | |
|     label: cancel_btn || l('WEB_CANCEL', 'Cancel'),
 | |
|     onPress: function() {
 | |
|       onCancel && onCancel(popup_el);
 | |
|     },
 | |
|     close: true
 | |
|   }, {
 | |
|     label: confirm_btn || l('WEB_OK', 'OK'),
 | |
|     onPress: function() {
 | |
|       onConfirm && onConfirm(popup_el);
 | |
|       TPopups.close(popup_el);
 | |
|     },
 | |
|     enter: true
 | |
|   }]);
 | |
|   return popup_el;
 | |
| }
 | |
| 
 | |
| function addEvent(el, event, handler) {
 | |
|   gec(el, function() {
 | |
|     var events = event.split(/\s+/);
 | |
|     for (var i = 0; i < events.length; i++) {
 | |
|       if (this.addEventListener) {
 | |
|         this.addEventListener(events[i], handler, false);
 | |
|       } else {
 | |
|         this.attachEvent('on' + events[i], handler);
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function removeEvent(el, event, handler) {
 | |
|   gec(el, function() {
 | |
|     var events = event.split(/\s+/);
 | |
|     for (var i = 0; i < events.length; i++) {
 | |
|       if (this.removeEventListener) {
 | |
|         this.removeEventListener(events[i], handler);
 | |
|       } else {
 | |
|         this.detachEvent('on' + events[i], handler);
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function addEventOnce(el, event, handler) {
 | |
|   var once_handler = function(e) {
 | |
|     removeEvent(el, event, once_handler);
 | |
|     handler(e);
 | |
|   };
 | |
|   addEvent(el, event, once_handler);
 | |
| }
 | |
| function triggerEvent(el, event_type, init_dict) {
 | |
|   gec(el, function() {
 | |
|     var event = new CustomEvent(event_type, init_dict);
 | |
|     this.dispatchEvent(event);
 | |
|   });
 | |
| }
 | |
| 
 | |
| function geById(el_or_id) {
 | |
|   if (typeof el_or_id == 'string' || el_or_id instanceof String) {
 | |
|     return document.getElementById(el_or_id);
 | |
|   } else if (el_or_id instanceof HTMLElement) {
 | |
|     return el_or_id;
 | |
|   }
 | |
|   return null;
 | |
| }
 | |
| 
 | |
| function gec(el, callback, context) {
 | |
|   var list = ge(el, context);
 | |
|   for (var i = 0, l = list.length; i < l; i++) {
 | |
|     var result = callback.call(list[i], list[i], i, list);
 | |
|     if (result === false) {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| function ge(el, context) {
 | |
|   var list = [];
 | |
|   if (typeof el === 'string') {
 | |
|     list = (ge1(context) || document).querySelectorAll(el);
 | |
|   } else if (el instanceof Node || el instanceof Window) {
 | |
|     list = [el];
 | |
|   } else if (el instanceof NodeList) {
 | |
|     list = el;
 | |
|   } else if (Array.isArray(el)) {
 | |
|     list = el;
 | |
|   } else if (el) {
 | |
|     console.warn('unknown type of el', el);
 | |
|     return [el];
 | |
|   }
 | |
|   if (list instanceof NodeList) {
 | |
|     list = Array.prototype.slice.call(list);
 | |
|   }
 | |
|   return list;
 | |
| }
 | |
| function ge1(el, context) {
 | |
|   if (typeof el === 'string') {
 | |
|     return (ge1(context) || document).querySelector(el);
 | |
|   } else if (el instanceof Node || el instanceof Window) {
 | |
|     return el;
 | |
|   } else if (el instanceof NodeList) {
 | |
|     return el.item(0);
 | |
|   } else if (el instanceof Array) {
 | |
|     return el[0];
 | |
|   } else if (el) {
 | |
|     console.warn('unknown type of el', el);
 | |
|     return el;
 | |
|   }
 | |
|   return null;
 | |
| }
 | |
| function newEl(tag, cl, html, styles) {
 | |
|   var el = document.createElement((tag || 'DIV').toUpperCase());
 | |
|   if (cl) el.className = cl;
 | |
|   if (styles) {
 | |
|     for (var k in styles) {
 | |
|       el.style[k] = styles[k];
 | |
|     }
 | |
|   }
 | |
|   if (html) {
 | |
|     el.innerHTML = html;
 | |
|   }
 | |
|   return el;
 | |
| }
 | |
| function gpeByClass(el, cl) {
 | |
|   if (!el) return null;
 | |
|   while (el = el.parentNode) {
 | |
|     if (hasClass(el, cl)) break;
 | |
|   }
 | |
|   return el || null;
 | |
| }
 | |
| function elInBody(el) {
 | |
|   if (!el) return false;
 | |
|   while (el = el.parentNode) {
 | |
|     if (el === document.body) return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| function getCoords(callback, el) {
 | |
|   var rect = {};
 | |
|   if (el = ge1(el)) {
 | |
|     rect = el.getBoundingClientRect();
 | |
|   }
 | |
|   var docEl = document.documentElement;
 | |
|   var coords = {};
 | |
|   if (inFullFrame()) {
 | |
|     PostMessage.send({event: 'get_coords'}, function(coords) {
 | |
|       coords.inFrame = true;
 | |
|       if (el) {
 | |
|         coords.elTop = rect.top + coords.frameTop;
 | |
|         coords.elBottom = rect.bottom + coords.frameTop;
 | |
|         coords.elLeft = rect.left + coords.frameLeft;
 | |
|         coords.elRight = rect.right + coords.frameLeft;
 | |
|         coords.elWidth = rect.width;
 | |
|         coords.elHeight = rect.height;
 | |
|       }
 | |
|       callback && callback(coords);
 | |
|     });
 | |
|     return;
 | |
|   } else {
 | |
|     if (el) {
 | |
|       coords.elTop = rect.top;
 | |
|       coords.elBottom = rect.bottom;
 | |
|       coords.elLeft = rect.left;
 | |
|       coords.elRight = rect.right;
 | |
|       coords.elWidth = rect.width;
 | |
|       coords.elHeight = rect.height;
 | |
|     }
 | |
|     coords.scrollTop = window.pageYOffset;
 | |
|     coords.scrollLeft = window.pageXOffset;
 | |
|     coords.clientWidth = docEl.clientWidth;
 | |
|     coords.clientHeight = docEl.clientHeight;
 | |
|     callback && callback(coords);
 | |
|   }
 | |
| }
 | |
| function scrollToY(y) {
 | |
|   if (inFullFrame()) {
 | |
|     PostMessage.send({event: 'scroll_to', y: y});
 | |
|   } else {
 | |
|     window.scrollTo(0, y);
 | |
|   }
 | |
| }
 | |
| 
 | |
| function addClass(el, cl) {
 | |
|   gec(el, function() {
 | |
|     var cls = cl.split(/\s+/);
 | |
|     for (var i = 0; i < cls.length; i++) {
 | |
|       this.classList.add(cls[i]);
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function removeClass(el, cl) {
 | |
|   gec(el, function() {
 | |
|     var cls = cl.split(/\s+/);
 | |
|     for (var i = 0; i < cls.length; i++) {
 | |
|       this.classList.remove(cls[i]);
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function toggleClass(el, cl, add) {
 | |
|   gec(el, function() {
 | |
|     var cls = cl.split(/\s+/);
 | |
|     for (var i = 0; i < cls.length; i++) {
 | |
|       cl = cls[i];
 | |
|       var add_cl = (typeof add !== 'undefined') ? add : !hasClass(this, cl);
 | |
|       add_cl ? this.classList.add(cl) : this.classList.remove(cl);
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function hasClass(el, cl) {
 | |
|   var item = ge1(el);
 | |
|   return (item && item.classList && item.classList.contains(cl));
 | |
| }
 | |
| function removeEl(el) {
 | |
|   gec(el, function() {
 | |
|     if (this && this.parentNode) {
 | |
|       this.parentNode.removeChild(this);
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function getHtml(el, context) {
 | |
|   var item = ge1(el, context);
 | |
|   return item ? item.innerHTML : null;
 | |
| }
 | |
| function setHtml(el, html) {
 | |
|   gec(el, function() {
 | |
|     if (this) {
 | |
|       this.innerHTML = html;
 | |
|     }
 | |
|   });
 | |
| }
 | |
| function getAttr(el, attr) {
 | |
|   var item = ge1(el);
 | |
|   return item ? item.getAttribute(attr) : null;
 | |
| }
 | |
| function setAttr(el, attr, value) {
 | |
|   gec(el, function() {
 | |
|     if (this) {
 | |
|       this.setAttribute(attr, value);
 | |
|     }
 | |
|   });
 | |
| }
 | |
| 
 | |
| function isLSEnabled() {
 | |
|   try {
 | |
|     return window.localStorage ? true : false;
 | |
|   } catch (e) {
 | |
|     return false;
 | |
|   }
 | |
| }
 | |
| function parseHeaders(headers) {
 | |
|   var headers_strs = headers.replace(/^\s+|\s+$/g, '').split(/[\r\n]+/);
 | |
|   var headers_arr = [];
 | |
|   for (var i = 0; i < headers_strs.length; i++) {
 | |
|     var header_str = headers_strs[i];
 | |
|     var parts = header_str.split(': ');
 | |
|     var name = parts.shift().toLowerCase();
 | |
|     var value = parts.join(': ');
 | |
|     headers_arr.push({name: name, value: value});
 | |
|   }
 | |
|   return headers_arr;
 | |
| }
 | |
| function setLS(xhr) {
 | |
|   if (!isLSEnabled()) return;
 | |
|   try {
 | |
|     var headers = parseHeaders(xhr.getAllResponseHeaders());
 | |
|     for (var i = 0; i < headers.length; i++) {
 | |
|       var header = headers[i];
 | |
|       if (header.name == 'x-set-local-storage') {
 | |
|         var arr = header.value.split('=');
 | |
|         var key = decodeURIComponent(arr[0]);
 | |
|         var val = decodeURIComponent(arr[1]);
 | |
|         if (val.length) {
 | |
|           localStorage.setItem(key, val);
 | |
|         } else {
 | |
|           localStorage.removeItem(key);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } catch (e) {}
 | |
| }
 | |
| function getLSString() {
 | |
|   if (!isLSEnabled()) return false;
 | |
|   var arr = [];
 | |
|   for (var i = 0; i < localStorage.length; i++) {
 | |
|     var key = localStorage.key(i);
 | |
|     arr.push(encodeURIComponent(key) + '=' + encodeURIComponent(localStorage[key]));
 | |
|   }
 | |
|   return arr.join('; ');
 | |
| }
 | |
| 
 | |
| function getXHR() {
 | |
|   if (navigator.appName == "Microsoft Internet Explorer"){
 | |
|     return new ActiveXObject("Microsoft.XMLHTTP");
 | |
|   } else {
 | |
|     return new XMLHttpRequest();
 | |
|   }
 | |
| }
 | |
| 
 | |
| function xhrRequest(href, postdata, onCallback, retry_delay) {
 | |
|   var xhr = getXHR(), type = 'GET', data = null, ls_header;
 | |
|   if (postdata !== false) {
 | |
|     type = 'POST';
 | |
|     var data_arr = [];
 | |
|     for (var field in postdata) {
 | |
|       data_arr.push(encodeURIComponent(field) + '=' + encodeURIComponent(postdata[field]));
 | |
|     }
 | |
|     data = data_arr.join('&');
 | |
|   }
 | |
|   xhr.open(type, href);
 | |
|   if (postdata !== false) {
 | |
|     xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
 | |
|   }
 | |
|   xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
 | |
|   if (ls_header = getLSString()) {
 | |
|     xhr.setRequestHeader('X-Local-Storage', ls_header);
 | |
|   }
 | |
|   xhr.onerror = function() {
 | |
|     if (xhr._retried) return;
 | |
|     xhr._retried = true;
 | |
|     retry_delay = retry_delay || 1000;
 | |
|     if (retry_delay > 60000) {
 | |
|       onCallback && onCallback('Server unavailable');
 | |
|       return;
 | |
|     }
 | |
|     setTimeout(function() {
 | |
|       xhrRequest(href, postdata, onCallback, retry_delay * 2);
 | |
|     }, retry_delay);
 | |
|   };
 | |
|   xhr.onreadystatechange = function() {
 | |
|     if (xhr.readyState == 4) {
 | |
|       setLS(xhr);
 | |
|       if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
 | |
|         try {
 | |
|           var result = JSON.parse(xhr.responseText);
 | |
|         } catch(e) {
 | |
|           var result = {};
 | |
|         }
 | |
|         if (xhr.status == 401) { // Unauthorized
 | |
|           TWidgetAuth.reload();
 | |
|           return;
 | |
|         }
 | |
|         if (result.error && result.flood_wait) {
 | |
|           console.log('flood_wait', result.flood_wait);
 | |
|           setTimeout(function() {
 | |
|             xhrRequest(href, postdata, onCallback);
 | |
|           }, result.flood_wait * 1000);
 | |
|           return;
 | |
|         }
 | |
|         onCallback && onCallback(null, result);
 | |
|       } else {
 | |
|         xhr.onerror();
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   xhr.withCredentials = true;
 | |
|   xhr.send(data);
 | |
|   return xhr;
 | |
| }
 | |
| 
 | |
| function xhrJsonRequest(href, onCallback) {
 | |
|   var xhr = getXHR();
 | |
|   xhr.open('get', href);
 | |
|   if (xhr.overrideMimeType) {
 | |
|     xhr.overrideMimeType('text/plain; charset=x-user-defined');
 | |
|   } else {
 | |
|     xhr.setRequestHeader('Accept-Charset', 'x-user-defined');
 | |
|   }
 | |
|   xhr.onerror = function() {
 | |
|     onCallback({error: 'XHR_ERROR'});
 | |
|   }
 | |
|   xhr.onreadystatechange = function() {
 | |
|     if (xhr.readyState == 4) {
 | |
|       var result;
 | |
|       if (typeof xhr.responseBody == 'undefined' &&
 | |
|           xhr.responseText && xhr.status == 200) {
 | |
|         try {
 | |
|           result = JSON.parse(xhr.responseText);
 | |
|         } catch(e) {
 | |
|           result = {error: 'JSON_PARSE_FAILED'};
 | |
|         }
 | |
|       } else {
 | |
|         result = {error: 'HTTP_ERROR_' + xhr.status};
 | |
|       }
 | |
|       onCallback(result);
 | |
|     }
 | |
|   };
 | |
|   xhr.send(null);
 | |
|   return xhr;
 | |
| }
 | |
| 
 | |
| function xhrUploadRequest(href, params, onCallback, onProgress) {
 | |
|   var xhr = getXHR(), data = new FormData(), ls_header;
 | |
|   xhr.open('POST', href, true);
 | |
|   xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
 | |
|   if (ls_header = getLSString()) {
 | |
|     xhr.setRequestHeader('X-Local-Storage', ls_header);
 | |
|   }
 | |
|   xhr.upload.addEventListener('progress', function(event) {
 | |
|     if (event.lengthComputable) {
 | |
|       onProgress && onProgress(event.loaded, event.total);
 | |
|     }
 | |
|   });
 | |
|   xhr.onerror = function() {
 | |
|     onCallback && onCallback('Server unavailable');
 | |
|   };
 | |
|   xhr.onreadystatechange = function() {
 | |
|     if (xhr.readyState == 4) {
 | |
|       setLS(xhr);
 | |
|       if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
 | |
|         try {
 | |
|           var result = JSON.parse(xhr.responseText);
 | |
|         } catch(e) {
 | |
|           var result = {};
 | |
|         }
 | |
|         if (result.error && result.flood_wait) {
 | |
|           console.log('flood_wait', result.flood_wait);
 | |
|           setTimeout(function() {
 | |
|             xhrUploadRequest(href, params, onCallback, onProgress);
 | |
|           }, result.flood_wait * 1000);
 | |
|           return;
 | |
|         }
 | |
|         onCallback && onCallback(null, result);
 | |
|       } else {
 | |
|         xhr.onerror();
 | |
|       }
 | |
|     }
 | |
|   };
 | |
|   for (var k in params) {
 | |
|     var value = params[k];
 | |
|     if (value instanceof File) {
 | |
|       data.append(k, value, value.name);
 | |
|     } else {
 | |
|       data.append(k, value);
 | |
|     }
 | |
|   }
 | |
|   xhr.withCredentials = true;
 | |
|   xhr.send(data);
 | |
|   return xhr;
 | |
| }
 | |
| 
 | |
| window.TWidgetAuth = {
 | |
|   init: function(options) {
 | |
|     options = options || {};
 | |
|     TWidgetAuth.options = options;
 | |
|   },
 | |
|   apiRequest: function(method, params, callback) {
 | |
|     var options = TWidgetAuth.options || {};
 | |
|     if (!options.api_url) {
 | |
|       console.warn('API url not found');
 | |
|       return null;
 | |
|     }
 | |
|     params.method = method;
 | |
|     return xhrRequest(options.api_url, params, callback);
 | |
|   },
 | |
|   uploadRequest: function(params, onCallback, onProgress) {
 | |
|     var options = TWidgetAuth.options || {};
 | |
|     if (!options.upload_url) {
 | |
|       console.warn('Upload url not found');
 | |
|       return null;
 | |
|     }
 | |
|     return xhrUploadRequest(options.upload_url, params, onCallback, onProgress);
 | |
|   },
 | |
|   logIn: function() {
 | |
|     var options = TWidgetAuth.options || {};
 | |
|     if (!options.bot_id) {
 | |
|       console.warn('Bot id not found');
 | |
|       return;
 | |
|     }
 | |
|     if (TWidgetAuth.isLoggedIn()) {
 | |
|       return;
 | |
|     }
 | |
|     Telegram.Login.auth({bot_id: options.bot_id, lang: 'en'}, function(user) {
 | |
|       if (user) {
 | |
|         xhrRequest('/auth', user, function(err, result) {
 | |
|           if (result.ok) {
 | |
|             TWidgetAuth.reload(result.host);
 | |
|           } else {
 | |
|             location.reload();
 | |
|           }
 | |
|         });
 | |
|       }
 | |
|     });
 | |
|   },
 | |
|   reload: function(host, callback) {
 | |
|     var xhr = getXHR(), data = null, ls_header;
 | |
|     var url = location.href;
 | |
|     if (host) {
 | |
|       var a = newEl('a');
 | |
|       a.href = url; a.hostname = host; url = a.href;
 | |
|     }
 | |
|     xhr.open('GET', url);
 | |
|     xhr.setRequestHeader('X-Requested-With', 'relogin');
 | |
|     if (ls_header = getLSString()) {
 | |
|       xhr.setRequestHeader('X-Local-Storage', ls_header);
 | |
|     }
 | |
|     xhr.onreadystatechange = function() {
 | |
|       if (xhr.readyState == 4) {
 | |
|         setLS(xhr);
 | |
|         if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
 | |
|           document.open();
 | |
|           document.write(xhr.responseText);
 | |
|           document.close();
 | |
|           callback && callback();
 | |
|         } else {
 | |
|           location.reload();
 | |
|         }
 | |
|       }
 | |
|     };
 | |
|     xhr.onerror = function() {
 | |
|       location.reload();
 | |
|     };
 | |
|     xhr.withCredentials = true;
 | |
|     xhr.send();
 | |
|   },
 | |
|   isLoggedIn: function() {
 | |
|     var options = TWidgetAuth.options || {};
 | |
|     return options && !options.unauth;
 | |
|   }
 | |
| };
 | |
| window.apiRequest = TWidgetAuth.apiRequest;
 | |
| window.uploadRequest = TWidgetAuth.uploadRequest;
 | |
| 
 | |
| function loadImage(file, callback) {
 | |
|   var image = new Image();
 | |
|   image.onload = function() {
 | |
|     var w = image.naturalWidth;
 | |
|     var h = image.naturalHeight;
 | |
|     callback && callback(null, {
 | |
|       url:    image.src,
 | |
|       width:  w,
 | |
|       height: h,
 | |
|       image:  image
 | |
|     });
 | |
|   };
 | |
|   image.onerror = function() {
 | |
|     callback && callback('LOAD_FAILED');
 | |
|   };
 | |
|   image.src = URL.createObjectURL(file);
 | |
| }
 | |
| 
 | |
| function initWidgetFrame(options) {
 | |
|   TWidget.options = options || {};
 | |
|   if (window.devicePixelRatio >= 2) {
 | |
|     addClass(document.body, 'r2x');
 | |
|   }
 | |
|   if (TWidget.options.auto_height ||
 | |
|       TWidget.options.auto_width) {
 | |
|     addEvent(window, 'resize', checkFrameSize);
 | |
|     checkFrameSize();
 | |
|   }
 | |
|   addEvent(window, 'message', PostMessage.onMessage);
 | |
|   addEvent(window, 'focus blur', function() {
 | |
|     triggerEvent(window, 'tg:focuschange');
 | |
|   });
 | |
|   PostMessage.send({event: 'ready'});
 | |
| }
 | |
| 
 | |
| var frameLastHeight = null,
 | |
|     frameLastWidth = null,
 | |
|     frameWasVisible = false;
 | |
| function checkFrameSize() {
 | |
|   var height, width, style;
 | |
|   if (document.body) {
 | |
|     if (TWidget.options.include_absolute_elems) {
 | |
|       if (document.body.querySelectorAll) {
 | |
|         document.body.querySelectorAll('*').forEach(function(el) {
 | |
|             var rect = el.getBoundingClientRect();
 | |
|             if (!width || width < rect.right) width = rect.right;
 | |
|             if (!height || height < rect.bottom) height = rect.bottom;
 | |
|         });
 | |
|       }
 | |
|     } else {
 | |
|       if (window.getComputedStyle) {
 | |
|         style = window.getComputedStyle(document.body);
 | |
|         height = style.height;
 | |
|         if (height.substr(-2) == 'px') {
 | |
|           height = height.slice(0, -2);
 | |
|         }
 | |
|         width = style.width;
 | |
|         if (width.substr(-2) == 'px') {
 | |
|           width = width.slice(0, -2);
 | |
|         }
 | |
|       } else {
 | |
|         height = document.body.offsetHeight;
 | |
|         width = document.body.offsetWidth;
 | |
|       }
 | |
|     }
 | |
|     var data = {event: 'resize'}, resized = false;
 | |
|     if (TWidget.options.auto_height) {
 | |
|       height = Math.ceil(height);
 | |
|       if (height != frameLastHeight) {
 | |
|         frameLastHeight = height;
 | |
|         data.height = height;
 | |
|         resized = true;
 | |
|       }
 | |
|     }
 | |
|     if (TWidget.options.auto_width) {
 | |
|       width = Math.ceil(width);
 | |
|       if (width != frameLastWidth) {
 | |
|         frameLastWidth = width;
 | |
|         data.width = width;
 | |
|         resized = true;
 | |
|       }
 | |
|     }
 | |
|     if (resized) {
 | |
|       PostMessage.send(data);
 | |
|     }
 | |
|   }
 | |
|   requestAnimationFrame(checkFrameSize);
 | |
| }
 | |
| 
 | |
| 
 | |
| (function() {
 | |
|   var ua = navigator.userAgent.toLowerCase();
 | |
|   var browser = {
 | |
|     opera: (/opera/i.test(ua) || /opr/i.test(ua)),
 | |
|     msie: (/msie/i.test(ua) && !/opera/i.test(ua) || /trident\//i.test(ua)) || /edge/i.test(ua),
 | |
|     msie_edge: (/edge/i.test(ua) && !/opera/i.test(ua)),
 | |
|     mozilla: /firefox/i.test(ua),
 | |
|     chrome: /chrome/i.test(ua) && !/edge/i.test(ua),
 | |
|     safari: (!(/chrome/i.test(ua)) && /webkit|safari|khtml/i.test(ua)),
 | |
|     iphone: /iphone/i.test(ua),
 | |
|     ipod: /ipod/i.test(ua),
 | |
|     ipad: /ipad/i.test(ua),
 | |
|     android: /android/i.test(ua),
 | |
|     mobile: /iphone|ipod|ipad|opera mini|opera mobi|iemobile|android/i.test(ua),
 | |
|     safari_mobile: /iphone|ipod|ipad/i.test(ua),
 | |
|     opera_mobile: /opera mini|opera mobi/i.test(ua),
 | |
|     opera_mini: /opera mini/i.test(ua),
 | |
|     mac: /mac/i.test(ua),
 | |
|   };
 | |
| 
 | |
|   function formatDateTime(datetime) {
 | |
|     var date = new Date(datetime);
 | |
|     var cur_date = new Date();
 | |
|     if (cur_date.getFullYear() == date.getFullYear() &&
 | |
|         cur_date.getMonth() == date.getMonth() &&
 | |
|         cur_date.getDate() == date.getDate()) {
 | |
|       return formatTime(datetime);
 | |
|     }
 | |
|     return formatDate(datetime);
 | |
|   }
 | |
| 
 | |
|   function formatDate(datetime) {
 | |
|     var date = new Date(datetime);
 | |
|     var cur_date = new Date();
 | |
|     var j = date.getDate();
 | |
|     var M = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()];
 | |
|     var Y = date.getFullYear();
 | |
|     if (cur_date.getFullYear() == date.getFullYear()) {
 | |
|       return M + ' ' + j;
 | |
|     }
 | |
|     return M + ' ' + j + ', ' + Y;
 | |
|   }
 | |
| 
 | |
|   function formatTime(datetime) {
 | |
|     var date = new Date(datetime);
 | |
|     var H = date.getHours();
 | |
|     if (H < 10) H = '0' + H;
 | |
|     var i = date.getMinutes();
 | |
|     if (i < 10) i = '0' + i;
 | |
|     if (H && i) {
 | |
|       return H + ':' + i;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function formatDuration(duration) {
 | |
|     duration = Math.floor(duration);
 | |
|     duration = Math.max(0, duration);
 | |
|     var duration_str = '';
 | |
|     if (duration >= 3600) {
 | |
|       var hours = Math.floor(duration / 3600);
 | |
|       duration_str += hours + ':';
 | |
|       var minutes = Math.floor((duration % 3600) / 60);
 | |
|       if (minutes < 10) minutes = '0' + minutes;
 | |
|     } else {
 | |
|       var minutes = Math.floor(duration / 60);
 | |
|     }
 | |
|     duration_str += minutes + ':';
 | |
|     var seconds = duration % 60;
 | |
|     if (seconds < 10) seconds = '0' + seconds;
 | |
|     duration_str += seconds;
 | |
|     return duration_str;
 | |
|   }
 | |
| 
 | |
|   function doesSupportEmoji() {
 | |
|     var context, smile, canvas = document.createElement('canvas');
 | |
|     if (!canvas.getContext) return false;
 | |
|     context = canvas.getContext('2d');
 | |
|     if (typeof context.fillText != 'function') return false;
 | |
|     smile = '#' + String.fromCharCode(65039) + String.fromCharCode(8419);
 | |
|     context.textBaseline = 'top';
 | |
|     context.font = '32px Arial';
 | |
|     context.fillText(smile, 0, 0);
 | |
|     if (context.getImageData(16, 16, 1, 1).data[0] === 0) return false;
 | |
|     var div = document.createElement('div');
 | |
|     div.style.position = 'absolute';
 | |
|     div.style.overflow = 'hidden';
 | |
|     div.style.top = '-1000px';
 | |
|     var span = document.createElement('span');
 | |
|     div.style.fontSize = '16px';
 | |
|     span.innerHTML = smile;
 | |
|     div.appendChild(span);
 | |
|     document.body.insertBefore(div, document.body.firstChild);
 | |
|     var width = span.offsetWidth;
 | |
|     document.body.removeChild(div);
 | |
|     if (width < 18) return false;
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   function cloneArr(arrLike) {
 | |
|     return Array.prototype.slice.apply(arrLike);
 | |
|   }
 | |
| 
 | |
|   var loadedLibs = {};
 | |
|   function loadLib(file, callback) {
 | |
|     if (!loadedLibs[file]) {
 | |
|       loadedLibs[file] = {
 | |
|         loaded: null,
 | |
|         callbacks: [callback]
 | |
|       };
 | |
|       var script = document.createElement('script');
 | |
|       script.type = 'text/javascript';
 | |
|       script.async = true;
 | |
|       script.src = file;
 | |
|       script.onerror = function() {
 | |
|         loadedLibs[file].loaded = false;
 | |
|         applyCallbacks(loadedLibs[file].callbacks, loadedLibs[file].loaded);
 | |
|       }
 | |
|       script.onload = function() {
 | |
|         loadedLibs[file].loaded = true;
 | |
|         applyCallbacks(loadedLibs[file].callbacks, loadedLibs[file].loaded);
 | |
|       }
 | |
|       var head = document.getElementsByTagName('head')[0];
 | |
|       head.appendChild(script);
 | |
|       return script;
 | |
|     } else if (loadedLibs[file].loaded === null) {
 | |
|       loadedLibs[file].callbacks.push(callback);
 | |
|     } else {
 | |
|       callback(loadedLibs[file].loaded);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var webpNativeSupport = null, webpFallbackSupport = null, webpImage = null, webpCallbacks = [];
 | |
|   function applyCallbacks(callbacks) {
 | |
|     var args = cloneArr(arguments); args.shift();
 | |
|     for (var i = 0; i < callbacks.length; i++) {
 | |
|       callbacks[i].apply(null, args);
 | |
|     }
 | |
|   }
 | |
|   function doesSupportWebp(callback) {
 | |
|     if (webpFallbackSupport !== null) {
 | |
|       callback(webpNativeSupport, webpFallbackSupport);
 | |
|     } else {
 | |
|       webpCallbacks.push(callback);
 | |
|       if (!webpImage) {
 | |
|         webpImage = new Image();
 | |
|         webpImage.onerror = webpImage.onload = function() {
 | |
|           if (this.width === 2 && this.height === 1) {
 | |
|             webpNativeSupport = true;
 | |
|             webpFallbackSupport = false;
 | |
|             applyCallbacks(webpCallbacks, webpNativeSupport, webpFallbackSupport);
 | |
|           } else {
 | |
|             webpNativeSupport = false;
 | |
|             var script = document.createElement('script');
 | |
|             script.type = 'text/javascript';
 | |
|             script.async = true;
 | |
|             script.src = 'js/libwebp-0.2.0.js';
 | |
|             script.onerror = function() {
 | |
|               webpFallbackSupport = false;
 | |
|               applyCallbacks(webpCallbacks, webpNativeSupport, webpFallbackSupport);
 | |
|             }
 | |
|             script.onload = function() {
 | |
|               webpFallbackSupport = true;
 | |
|               applyCallbacks(webpCallbacks, webpNativeSupport, webpFallbackSupport);
 | |
|             }
 | |
|             var head = document.getElementsByTagName('head')[0];
 | |
|             head.appendChild(script);
 | |
|           }
 | |
|         }
 | |
|         webpImage.src = 'data:image/webp;base64,UklGRjIAAABXRUJQVlA4ICYAAACyAgCdASoCAAEALmk0mk0iIiIiIgBoSygABc6zbAAA/v56QAAAAA==';
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   function getPngDataUrlFromWebp(data) {
 | |
|     var decoder = new WebPDecoder();
 | |
|     var config = decoder.WebPDecoderConfig;
 | |
|     var buffer = config.j || config.output;
 | |
|     var bitstream = config.input;
 | |
|     if (!decoder.WebPInitDecoderConfig(config)) {
 | |
|       throw new Error('[webpjs] Library version mismatch!');
 | |
|     }
 | |
|     var StatusCode = decoder.VP8StatusCode;
 | |
|     status = decoder.WebPGetFeatures(data, data.length, bitstream);
 | |
|     if (status != (StatusCode.VP8_STATUS_OK || 0)) {
 | |
|       throw new Error('[webpjs] status error');
 | |
|     }
 | |
|     var mode = decoder.WEBP_CSP_MODE;
 | |
|     buffer.colorspace = mode.MODE_RGBA;
 | |
|     buffer.J = 4;
 | |
|     try {
 | |
|       status = decoder.WebPDecode(data, data.length, config);
 | |
|     } catch (e) {
 | |
|       status = e
 | |
|     }
 | |
|     var ok = (status == 0);
 | |
|     if (!ok) {
 | |
|       throw new Error('[webpjs] decoding failed');
 | |
|     }
 | |
|     var bitmap = buffer.c.RGBA.ma;
 | |
|     if (!bitmap) {
 | |
|       throw new Error('[webpjs] bitmap error');
 | |
|     }
 | |
|     var biHeight = buffer.height;
 | |
|     var biWidth = buffer.width;
 | |
|     var canvas = document.createElement('canvas');
 | |
|     var context = canvas.getContext('2d');
 | |
|     canvas.height = biHeight;
 | |
|     canvas.width = biWidth;
 | |
|     var output = context.createImageData(canvas.width, canvas.height);
 | |
|     var outputData = output.data;
 | |
|     for (var h = 0; h < biHeight; h++) {
 | |
|       for (var w = 0; w < biWidth; w++) {
 | |
|         outputData[0 + w * 4 + (biWidth * 4) * h] = bitmap[1 + w * 4 + (biWidth * 4) * h];
 | |
|         outputData[1 + w * 4 + (biWidth * 4) * h] = bitmap[2 + w * 4 + (biWidth * 4) * h];
 | |
|         outputData[2 + w * 4 + (biWidth * 4) * h] = bitmap[3 + w * 4 + (biWidth * 4) * h];
 | |
|         outputData[3 + w * 4 + (biWidth * 4) * h] = bitmap[0 + w * 4 + (biWidth * 4) * h];
 | |
|       }
 | |
|     }
 | |
|     context.putImageData(output, 0, 0);
 | |
|     return canvas.toDataURL('image/png');
 | |
|   }
 | |
| 
 | |
|   function proccessWebpImage(imgEl, failed_callback, success_callback) {
 | |
|     var imgEl = geById(imgEl);
 | |
|     if (!imgEl || imgEl.__inited) return;
 | |
|     imgEl.__inited = true;
 | |
|     failed_callback = failed_callback || function(){};
 | |
|     success_callback = success_callback || function(){};
 | |
|     doesSupportWebp(function(nativeSupport, fallbackSupport) {
 | |
|       var isImage, src;
 | |
|       var webpSrc = imgEl.getAttribute('data-webp');
 | |
|       if (imgEl.tagName && imgEl.tagName.toUpperCase() == 'IMG' && imgEl.src) {
 | |
|         isImage = true;
 | |
|         src = imgEl.src;
 | |
|       } else {
 | |
|         isImage = false;
 | |
|         var bgImage;
 | |
|         if (window.getComputedStyle) {
 | |
|           bgImage = window.getComputedStyle(imgEl).backgroundImage;
 | |
|         } else {
 | |
|           bgImage = imgEl.style && imgEl.style.backgroundImage;
 | |
|         }
 | |
|         src = bgImage.slice(4, -1).replace(/["|']/g, '');
 | |
|       }
 | |
|       var setImgSrc = function(src) {
 | |
|         if (isImage) {
 | |
|           imgEl.src = src;
 | |
|         } else {
 | |
|           imgEl.style.backgroundImage = "url('" + src + "')";
 | |
|         }
 | |
|         addClass(imgEl, 'webp_sticker_done');
 | |
|       };
 | |
|       if (nativeSupport) {
 | |
|         if (webpSrc) {
 | |
|           var img = new Image();
 | |
|           img.onload = function() {
 | |
|             setImgSrc(webpSrc);
 | |
|             success_callback();
 | |
|           }
 | |
|           img.onerror = function() {
 | |
|             failed_callback();
 | |
|           }
 | |
|           img.src = webpSrc;
 | |
|         } else {
 | |
|           success_callback();
 | |
|         }
 | |
|         return;
 | |
|       } else if (!fallbackSupport) {
 | |
|         failed_callback();
 | |
|         return;
 | |
|       }
 | |
|       if (hasClass(imgEl, 'webp_sticker_done')) {
 | |
|         success_callback();
 | |
|         return;
 | |
|       }
 | |
|       if (!src) {
 | |
|         failed_callback();
 | |
|         return;
 | |
|       }
 | |
|       if (webpSrc) {
 | |
|         src = webpSrc;
 | |
|       }
 | |
|       var xhr = getXHR();
 | |
|       xhr.open('get', src);
 | |
|       if (xhr.overrideMimeType) {
 | |
|         xhr.overrideMimeType('text/plain; charset=x-user-defined');
 | |
|       } else {
 | |
|         xhr.setRequestHeader('Accept-Charset', 'x-user-defined');
 | |
|       }
 | |
|       xhr.onreadystatechange = function() {
 | |
|         if (xhr.readyState == 4) {
 | |
|           if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
 | |
|             var rlen = xhr.responseText.length, uarr = new Uint8Array(rlen);
 | |
|             for (var i = 0; i < rlen; i++) {
 | |
|               uarr[i] = xhr.responseText.charCodeAt(i);
 | |
|             }
 | |
|             try {
 | |
|               var src = getPngDataUrlFromWebp(uarr);
 | |
|               if (isImage) {
 | |
|                 imgEl.src = src;
 | |
|               } else {
 | |
|                 imgEl.style.backgroundImage = "url('" + src + "')";
 | |
|               }
 | |
|               addClass(imgEl, 'webp_sticker_done');
 | |
|               success_callback();
 | |
|             } catch(e) {
 | |
|               failed_callback();
 | |
|             }
 | |
|           } else {
 | |
|             failed_callback();
 | |
|           }
 | |
|         }
 | |
|       };
 | |
|       xhr.send(null);
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   function proccessWebmImage(imageEl, failed_callback, success_callback) {
 | |
|     imageEl = geById(imageEl);
 | |
|     if (!imageEl || imageEl.__inited) return;
 | |
|     imageEl.__inited = true;
 | |
|     failed_callback = failed_callback || function(){};
 | |
|     success_callback = success_callback || function(){};
 | |
|     var videoEl = ge1('video', imageEl);
 | |
|     var imgEl = ge1('img', videoEl);
 | |
|     if (!videoEl) return;
 | |
|     var fallback = function() {
 | |
|       videoEl.parentNode.removeChild(videoEl);
 | |
|       imageEl.style.backgroundImage = 'none';
 | |
|       if (imgEl && imgEl.src) {
 | |
|         var img = new Image();
 | |
|         img.onload = function() {
 | |
|           imageEl.style.backgroundImage = "url('" + img.src + "')";
 | |
|         }
 | |
|         img.src = imgEl.src;
 | |
|       }
 | |
|       failed_callback();
 | |
|     };
 | |
|     if (browser.safari) {
 | |
|       fallback();
 | |
|       return;
 | |
|     }
 | |
|     enableInlineVideo(videoEl);
 | |
|     checkVideo(videoEl, fallback);
 | |
|     function videoStarted() {
 | |
|       removeEvent(videoEl, 'timeupdate', videoStarted);
 | |
|       imageEl.style.backgroundImage = 'none';
 | |
|       addClass(imgEl, 'webm_sticker_done');
 | |
|       success_callback();
 | |
|     }
 | |
|     addEvent(videoEl, 'timeupdate', videoStarted);
 | |
|   }
 | |
| 
 | |
|   function proccessEmoji(emojiEl, failed_callback, success_callback) {
 | |
|     emojiEl = geById(emojiEl);
 | |
|     if (!emojiEl || emojiEl.__inited) return;
 | |
|     emojiEl.__inited = true;
 | |
|     failed_callback = failed_callback || function(){};
 | |
|     success_callback = success_callback || function(){};
 | |
| 
 | |
|     var emoji_id = emojiEl.getAttribute('emoji-id');
 | |
|     if (!emoji_id) {
 | |
|       failed_callback();
 | |
|       return;
 | |
|     }
 | |
|     xhrJsonRequest('/i/emoji/' + emoji_id + '.json', function(emoji) {
 | |
|       if (emoji.error) {
 | |
|         failed_callback();
 | |
|         return;
 | |
|       }
 | |
|       var emoji_html = '', thumb_url = '', thumb_mime = '';
 | |
|       if (emoji.path) {
 | |
|         var size = emoji.size || (emoji.type == 'tgs' ? 512 : 100);
 | |
|         var thumb_svg = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ' + size + ' ' + size + '"><defs><linearGradient id="g" x1="-300%" x2="-200%" y1="0" y2="0"><stop offset="-10%" stop-opacity=".1"/><stop offset="30%" stop-opacity=".07"/><stop offset="70%" stop-opacity=".07"/><stop offset="110%" stop-opacity=".1"/><animate attributeName="x1" from="-300%" to="1200%" dur="3s" repeatCount="indefinite"/><animate attributeName="x2" from="-200%" to="1300%" dur="3s" repeatCount="indefinite"/></linearGradient></defs><path fill="url(#g)" d="' + emoji.path + '"/></svg>';
 | |
|         thumb_url = 'data:image/svg+xml,' + encodeURIComponent(thumb_svg);
 | |
|       }
 | |
|       if (emoji.type == 'tgs') {
 | |
|         if (!thumb_url) {
 | |
|           thumb_url = emoji.thumb;
 | |
|           thumb_mime = 'image/webp';
 | |
|         } else {
 | |
|           thumb_mime = 'image/svg+xml';
 | |
|         }
 | |
|         emoji_html = '<picture class="tg-emoji tg-emoji-tgs"><source type="application/x-tgsticker" srcset="' + emoji.emoji + '"><source type="' + thumb_mime + '" srcset="' + thumb_url + '"><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"></picture>';
 | |
|       } else if (emoji.type == 'webm') {
 | |
|         var wrap_attr = thumb_url ? ' style="background-image:url(\'' + thumb_url + '\');"' : '';
 | |
|         emoji_html = '<div class="tg-emoji tg-emoji-webm"' + wrap_attr + '><video src="' + emoji.emoji + '" width="100%" height="100%" preload muted autoplay loop playsinline disablepictureinpicture><img src="' + emoji.thumb + '"></video></div>';
 | |
|       } else if (emoji.type == 'webp') {
 | |
|         var wrap_attr = thumb_url ? ' style="background-image:url(\'' + thumb_url + '\');" data-webp="' + emoji.emoji + '"' : ' style="background-image:url(\'' + emoji.emoji + '\');"';
 | |
|         emoji_html = '<i class="tg-emoji tg-emoji-webp"' + wrap_attr + '></i>';
 | |
|       }
 | |
|       if (emoji_html) {
 | |
|         var emojiWrapEl = newEl('span', 'tg-emoji-wrap', emoji_html);
 | |
|         emojiEl.insertBefore(emojiWrapEl, emojiEl.firstChild);
 | |
|         if (emoji.type == 'tgs') {
 | |
|           gec('.tg-emoji-tgs', function() {
 | |
|             if (!RLottie.isSupported) {
 | |
|               failed_callback();
 | |
|             } else {
 | |
|               addEventOnce(this, 'tg:init', success_callback);
 | |
|               RLottie.init(this);
 | |
|             }
 | |
|           }, emojiWrapEl);
 | |
|         } else if (emoji.type == 'webm') {
 | |
|           gec('.tg-emoji-webm', function() {
 | |
|             TVideoSticker.init(this, failed_callback, success_callback);
 | |
|           }, emojiWrapEl);
 | |
|         } else if (emoji.type == 'webp') {
 | |
|           gec('.tg-emoji-webp', function() {
 | |
|             TSticker.init(this, failed_callback, success_callback);
 | |
|           }, emojiWrapEl);
 | |
|         }
 | |
|       } else {
 | |
|         failed_callback();
 | |
|       }
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   function checkVideo(el, error_callback) {
 | |
|     var timeout, eventAdded;
 | |
|     if (!eventAdded) {
 | |
|       function destroyCheck() {
 | |
|         clearTimeout(timeout);
 | |
|         removeEvent(el, 'canplay', onCanPlay);
 | |
|         removeEvent(el, 'error', onError);
 | |
|       }
 | |
|       function onCanPlay() {
 | |
|         destroyCheck();
 | |
|       }
 | |
|       function onError() {
 | |
|         destroyCheck();
 | |
|         error_callback();
 | |
|       }
 | |
|       eventAdded = true;
 | |
|       addEvent(el, 'canplay', onCanPlay);
 | |
|       addEvent(el, 'error', onError);
 | |
|     }
 | |
|     if (el.readyState >= 2) {
 | |
|       destroyCheck();
 | |
|     } else {
 | |
|       timeout = setTimeout(function() {
 | |
|         checkVideo(el, error_callback);
 | |
|       }, 50);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   window.TPost = {
 | |
|     init: function(postEl, options) {
 | |
|       postEl = geById(postEl);
 | |
|       options = options || {};
 | |
|       if (!postEl || postEl.__inited) return;
 | |
|       postEl.__inited = true;
 | |
|       if (window.RLottie) {
 | |
|         if (options.tgs_workers_limit) {
 | |
|           RLottie.WORKERS_LIMIT = options.tgs_workers_limit;
 | |
|         } else if (options.frame) {
 | |
|           RLottie.WORKERS_LIMIT = 1;
 | |
|         }
 | |
|       }
 | |
|       gec('time[datetime]', function() {
 | |
|         var datetime = this.getAttribute('datetime');
 | |
|         if (datetime) {
 | |
|           if (hasClass(this, 'datetime')) {
 | |
|             this.innerHTML = formatDate(datetime) + ' at ' + formatTime(datetime);
 | |
|           } else if (hasClass(this, 'time')) {
 | |
|             this.innerHTML = formatTime(datetime);
 | |
|           } else {
 | |
|             this.innerHTML = formatDateTime(datetime);
 | |
|           }
 | |
|         }
 | |
|       }, postEl);
 | |
|       gec('.js-message_text', function() {
 | |
|         TPost.initSpoilers(this, !gpeByClass(this, 'service_message'));
 | |
|         gec('tg-emoji', function() {
 | |
|           var emojiEl = this;
 | |
|           TEmoji.init(this, function() {
 | |
|             var wrapEl = gpeByClass(emojiEl, 'js-message_media') || postEl;
 | |
|             addClass(wrapEl, 'media_not_supported');
 | |
|             removeClass(postEl, 'no_bubble');
 | |
|           });
 | |
|         }, this);
 | |
|       }, postEl);
 | |
|       gec('.js-message_reply_text', function() {
 | |
|         TPost.initSpoilers(this);
 | |
|         gec('tg-emoji', function() {
 | |
|           TEmoji.init(this);
 | |
|         }, this);
 | |
|       }, postEl);
 | |
|       gec('.js-message_footer.compact', function() {
 | |
|         var timeEl = ge1('time[datetime]', this)
 | |
|           , textEl = this.previousElementSibling;
 | |
|         if (textEl && hasClass(textEl, 'js-message_media')) {
 | |
|           textEl = textEl.lastElementChild;
 | |
|         }
 | |
|         if (textEl && !textEl.__inited && hasClass(textEl, 'js-message_text')) {
 | |
|           var text_rect = textEl.getBoundingClientRect();
 | |
|           var tnode = textEl.firstChild;
 | |
|           while (tnode && tnode.nodeType == tnode.ELEMENT_NODE) {
 | |
|             tnode = tnode.firstChild;
 | |
|           }
 | |
|           if (tnode) {
 | |
|             var r = document.createRange();
 | |
|             r.setStart(tnode, 0);
 | |
|             r.setEnd(tnode, 1);
 | |
|             var char_rect = r.getBoundingClientRect();
 | |
|             textEl.__inited = true;
 | |
|             if (Math.abs(char_rect.right - text_rect.right) > 3) {
 | |
|               var infoEl = ge1('.js-message_info', this);
 | |
|               if (infoEl) {
 | |
|                 var shadowEl = document.createElement('span');
 | |
|                 shadowEl.style.display = 'inline-block';
 | |
|                 shadowEl.style.width = infoEl.offsetWidth + 'px';
 | |
|                 textEl.appendChild(shadowEl);
 | |
|                 addClass(textEl, 'before_footer');
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         }
 | |
|       }, postEl);
 | |
|       gec('.js-message_video_player', function() {
 | |
|         TVideo.init(this);
 | |
|       }, postEl);
 | |
|       gec('.js-message_photo', function() {
 | |
|         TPhoto.init(this);
 | |
|       }, postEl);
 | |
|       gec('.js-message_grouped_wrap', function() {
 | |
|         TGrouped.init(this);
 | |
|       }, postEl);
 | |
|       gec('.js-message_roundvideo_player', function() {
 | |
|         TRoundVideo.init(this);
 | |
|       }, postEl);
 | |
|       gec('.js-message_voice_player', function() {
 | |
|         TVoice.init(this);
 | |
|       }, postEl);
 | |
|       gec('.js-sticker_image', function() {
 | |
|         TSticker.init(this, function() {
 | |
|           addClass(postEl, 'media_not_supported');
 | |
|           removeClass(postEl, 'no_bubble');
 | |
|         });
 | |
|       }, postEl);
 | |
|       gec('.js-sticker_thumb', function() {
 | |
|         TSticker.init(this);
 | |
|       }, postEl);
 | |
|       gec('.js-tgsticker_image', function() {
 | |
|         var stickerEl = this;
 | |
|         var effectEl = ge1('.js-tgsticker_effect', postEl);
 | |
|         if (effectEl) {
 | |
|           addEventOnce(this, 'tg:play', function() {
 | |
|             RLottie.playOnce(effectEl);
 | |
|           });
 | |
|           addEvent(this, 'click', function(e) {
 | |
|             e.stopPropagation();
 | |
|             RLottie.playOnce(effectEl);
 | |
|           });
 | |
|         }
 | |
|         RLottie.init(this, {
 | |
|           playUntilEnd: this.hasAttribute('data-is-dice')
 | |
|         });
 | |
|       }, postEl);
 | |
|       gec('.js-tgsticker_effect', function() {
 | |
|         RLottie.init(this, {noAutoPlay: true});
 | |
|         var effectEl = this;
 | |
|         addEvent(this, 'tg:play', function() {
 | |
|           effectEl.style.visibility = 'visible';
 | |
|         });
 | |
|         addEvent(this, 'tg:pause', function() {
 | |
|           effectEl.style.visibility = 'hidden';
 | |
|         });
 | |
|       }, postEl);
 | |
|       gec('.js-videosticker', function() {
 | |
|         TVideoSticker.init(this, function() {
 | |
|           addClass(postEl, 'media_not_supported');
 | |
|           removeClass(postEl, 'no_bubble');
 | |
|         });
 | |
|       }, postEl);
 | |
|     },
 | |
|     view: function(postEl) {
 | |
|       postEl = geById(postEl);
 | |
|       if (!postEl) return;
 | |
|       var view = postEl.getAttribute('data-view');
 | |
|       if (view) {
 | |
|         var xhr = getXHR();
 | |
|         xhr.open('get', '/v/?views=' + encodeURIComponent(view));
 | |
|         xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
 | |
|         xhr.send(null);
 | |
|       }
 | |
|     },
 | |
|     initSpoilers: function(text_el, active) {
 | |
|       var spoilers = ge('tg-spoiler', text_el);
 | |
|       if (spoilers.length) {
 | |
|         TPost.wrapSpoilers(spoilers);
 | |
|         TPost.wrapTextNodes(text_el);
 | |
|         addClass(text_el, 'decorated-text');
 | |
|       }
 | |
|       TPost.hideSpoilers(text_el, active);
 | |
|     },
 | |
|     wrapSpoilers: function(spoilers) {
 | |
|       gec(spoilers, function() {
 | |
|         var inner_el = newEl('span', 'tg-spoiler-text');
 | |
|         while (this.firstChild) {
 | |
|           inner_el.appendChild(this.firstChild);
 | |
|         }
 | |
|         this.appendChild(inner_el);
 | |
|       });
 | |
|     },
 | |
|     wrapTextNodes: function(el) {
 | |
|       gec(el.childNodes, function() {
 | |
|         if (this.nodeType == this.TEXT_NODE) {
 | |
|           var text = newEl('span', 'd-text');
 | |
|           this.parentNode.insertBefore(text, this);
 | |
|           text.appendChild(this);
 | |
|         } else if (!this.classList.contains('tg-spoiler') && this.childNodes) {
 | |
|           TPost.wrapTextNodes(this);
 | |
|         }
 | |
|       });
 | |
|     },
 | |
|     hideSpoilers: function(text_el, active) {
 | |
|       var spoilers = ge('tg-spoiler', text_el);
 | |
|       if (spoilers.length) {
 | |
|         if (active) {
 | |
|           addClass(text_el, 'spoilers_active');
 | |
|           addEvent(spoilers, 'click', TPost.eSpoilerShow);
 | |
|         }
 | |
|         addClass(text_el, 'spoilers_hidden');
 | |
|       }
 | |
|     },
 | |
|     eSpoilerShow: function(e) {
 | |
|       var text_el = gpeByClass(this, 'spoilers_hidden');
 | |
|       if (!text_el) return false;
 | |
|       e.preventDefault();
 | |
|       e.stopImmediatePropagation();
 | |
|       addClass(text_el, 'spoilers_animate');
 | |
|       removeClass(text_el, 'spoilers_hidden');
 | |
|       var delay = 0;
 | |
|       gec('tg-spoiler', function() {
 | |
|         removeEvent(this, 'click', TPost.eSpoilerShow);
 | |
|         delay += this.innerText.length * 40;
 | |
|       }, text_el);
 | |
|       if (delay < 4000) delay = 4000;
 | |
|       if (delay > 45000) delay = 45000;
 | |
|       setTimeout(function() {
 | |
|         TPost.hideSpoilers(text_el, true);
 | |
|       }, delay);
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TPhoto = window.TPhoto = {
 | |
|     init: function(photoEl) {
 | |
|       photoEl = geById(photoEl);
 | |
|       if (!photoEl || photoEl.__inited) return;
 | |
|       photoEl.__inited = true;
 | |
|       var inGroup = hasClass(photoEl, 'grouped_media_wrap')
 | |
|         , opened
 | |
|         , overTo;
 | |
|       if (inGroup) {
 | |
|         addEvent(photoEl, 'click', function togglePhoto(e) {
 | |
|           if (e.metaKey || e.ctrlKey) return true;
 | |
|           e.stopPropagation();
 | |
|           if (!photoEl) return true;
 | |
|           if (opened) {
 | |
|             opened = false;
 | |
|             removeClass(photoEl, 'active');
 | |
|             overTo = setTimeout(function() {
 | |
|               removeClass(photoEl, 'over');
 | |
|             }, 200);
 | |
|           } else {
 | |
|             opened = true;
 | |
|             clearTimeout(overTo);
 | |
|             addClass(photoEl, 'over active');
 | |
|           }
 | |
|           e.preventDefault();
 | |
|           return false;
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TVideo = window.TVideo = {
 | |
|     init: function(playerEl) {
 | |
|       playerEl = geById(playerEl);
 | |
|       if (!playerEl || playerEl.__inited) return;
 | |
|       playerEl.__inited = true;
 | |
|       var videoEl = ge1('.js-message_video', playerEl)
 | |
|         , videoBluredEl = ge1('.js-message_video_blured', playerEl)
 | |
|         , playEl = ge1('.js-message_video_play', playerEl)
 | |
|         , durationEl = ge1('.js-message_video_duration', playerEl)
 | |
|         , inGroup = hasClass(playerEl, 'grouped_media_wrap')
 | |
|         , looped
 | |
|         , overTo;
 | |
|       if (!videoEl) return;
 | |
| 
 | |
|       looped = videoEl.hasAttribute('loop');
 | |
|       if (inGroup) {
 | |
|         addEvent(playerEl, 'click', function videoToggleInGroup(e) {
 | |
|           if (e.metaKey || e.ctrlKey) return true;
 | |
|           if (hasClass(e.target, 'message_media_view_in_telegram')) return true;
 | |
|           e.stopPropagation();
 | |
|           if (!playerEl) return true;
 | |
|           if (hasClass(playerEl, 'active')) {
 | |
|             removeClass(playerEl, 'active');
 | |
|             overTo = setTimeout(function() {
 | |
|               removeClass(playerEl, 'over');
 | |
|             }, 200);
 | |
|           } else {
 | |
|             clearTimeout(overTo);
 | |
|             addClass(playerEl, 'over active');
 | |
|           }
 | |
|           e.preventDefault();
 | |
|           return false;
 | |
|         });
 | |
|       }
 | |
|       if (videoEl.hasAttribute('playsinline')) {
 | |
|         enableInlineVideo(videoEl);
 | |
|         if (videoBluredEl) {
 | |
|           enableInlineVideo(videoBluredEl);
 | |
|         }
 | |
|       }
 | |
|       if (videoBluredEl) {
 | |
|         videoBluredEl.muted = true;
 | |
|       }
 | |
|       function fixControls() {
 | |
|         if (videoEl.controls) videoEl.controls = false;
 | |
|       }
 | |
|       var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
 | |
|       if (MutationObserver) {
 | |
|         (new MutationObserver(fixControls)).observe(videoEl, {attributes: true});
 | |
|       }
 | |
| 
 | |
|       checkVideo(videoEl, function() {
 | |
|         addClass(playerEl, 'not_supported');
 | |
|       });
 | |
|       addEvent(videoEl, 'play', function() {
 | |
|         fixControls();
 | |
|         addClass(playerEl, 'playing');
 | |
|         if (inGroup) {
 | |
|           clearTimeout(overTo);
 | |
|           addClass(playerEl, 'over active');
 | |
|         }
 | |
|         if (videoBluredEl) {
 | |
|           videoBluredEl.currentTime = videoEl.currentTime;
 | |
|           if (!browser.mobile) {
 | |
|             videoBluredEl.play();
 | |
|           }
 | |
|         }
 | |
|         if (!looped) {
 | |
|           triggerEvent(videoEl, 'tg:play', {bubbles: true});
 | |
|         }
 | |
|       });
 | |
|       addEvent(document, 'tg:play', function(e) {
 | |
|         if (e.target === videoEl || looped) return true;
 | |
|         if (!videoEl.paused) {
 | |
|           videoEl.pause();
 | |
|           if (videoBluredEl) {
 | |
|             videoBluredEl.pause();
 | |
|           }
 | |
|         }
 | |
|       });
 | |
|       addEvent(videoEl, 'pause', function() {
 | |
|         fixControls();
 | |
|         removeClass(playerEl, 'playing');
 | |
|         if (inGroup) {
 | |
|           removeClass(playerEl, 'active');
 | |
|           overTo = setTimeout(function() {
 | |
|             removeClass(playerEl, 'over');
 | |
|           }, 200);
 | |
|         }
 | |
|         if (videoBluredEl) {
 | |
|           videoBluredEl.currentTime = videoEl.currentTime;
 | |
|           videoBluredEl.pause();
 | |
|         }
 | |
|         if (looped) {
 | |
|           videoEl.play();
 | |
|         }
 | |
|       });
 | |
|       addEvent(videoEl, 'timeupdate', function(e) {
 | |
|         fixControls();
 | |
|         if (videoBluredEl && videoBluredEl.currentTime != videoEl.currentTime) {
 | |
|           videoBluredEl.currentTime = videoEl.currentTime;
 | |
|         }
 | |
|         if (durationEl && videoEl.duration) {
 | |
|           var duration = Math.floor(videoEl.duration);
 | |
|           durationEl.innerHTML = formatDuration(duration - videoEl.currentTime);
 | |
|         }
 | |
|       });
 | |
|       addEvent(videoEl, 'ended load', function(e) {
 | |
|         fixControls();
 | |
|         if (durationEl && videoEl.duration) {
 | |
|           var duration = Math.floor(videoEl.duration);
 | |
|           durationEl.innerHTML = formatDuration(duration);
 | |
|         }
 | |
|       });
 | |
|       if (looped) {
 | |
|         addEvent(document, 'touchstart', function(){ videoEl.play(); });
 | |
|       } else {
 | |
|         addClass(playerEl, 'ready');
 | |
|       }
 | |
|       if (playEl) {
 | |
|         addEvent(playEl, 'click', function toggleVideo(e) {
 | |
|           if (e.metaKey || e.ctrlKey) return true;
 | |
|           e.stopPropagation();
 | |
|           if (!videoEl) return true;
 | |
|           if (videoEl.paused) {
 | |
|             videoEl.play();
 | |
|             if (videoBluredEl) {
 | |
|               videoBluredEl.play();
 | |
|             }
 | |
|           } else {
 | |
|             videoEl.pause();
 | |
|             if (videoBluredEl) {
 | |
|               videoBluredEl.pause();
 | |
|             }
 | |
|           }
 | |
|           e.preventDefault();
 | |
|           return false;
 | |
|         });
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TGrouped = window.TGrouped = {
 | |
|     init: function(groupedWrapEl) {
 | |
|       groupedWrapEl = geById(groupedWrapEl);
 | |
|       if (!groupedWrapEl || groupedWrapEl.__inited) return;
 | |
|       groupedWrapEl.__inited = true;
 | |
|       var groupedEl = ge1('.js-message_grouped', groupedWrapEl)
 | |
|         , groupedLayerEl = ge1('.js-message_grouped_layer', groupedEl)
 | |
|         , thumbsEl = groupedLayerEl.children
 | |
|         , margin_w = +groupedWrapEl.getAttribute('data-margin-w') || 2
 | |
|         , margin_h = +groupedWrapEl.getAttribute('data-margin-h') || 2;
 | |
|       if (!thumbsEl.length) {
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       addEvent(window, 'resize', function() {
 | |
|         if (groupedLayerEl.offsetWidth != groupedEl.offsetWidth) {
 | |
|           recalcGrouped(groupedWrapEl.offsetWidth);
 | |
|         }
 | |
|       });
 | |
|       recalcGrouped(groupedWrapEl.offsetWidth);
 | |
| 
 | |
|       function updateThumb(thumbEl, x, y, width, height, th_width, th_height, position) {
 | |
|         if (!thumbEl) return;
 | |
|         var t = false, r = false, b = false, l = false;
 | |
|         for (var i = 0; i < position.length; i++) {
 | |
|           if      (position[i] == 't') t = true;
 | |
|           else if (position[i] == 'r') r = true;
 | |
|           else if (position[i] == 'b') b = true;
 | |
|           else if (position[i] == 'l') l = true;
 | |
|         }
 | |
|         thumbEl.style.left = x + 'px';
 | |
|         thumbEl.style.top = y + 'px';
 | |
|         thumbEl.style.width = width + 'px';
 | |
|         thumbEl.style.height = height + 'px';
 | |
|         thumbEl.style.marginRight = (!r ? margin_w : 0) + 'px';
 | |
|         thumbEl.style.marginBottom = (!b ? margin_h : 0) + 'px';
 | |
| 
 | |
|         var th_ratio = th_width / th_height;
 | |
|         var ratio    = +thumbEl.getAttribute('data-ratio') || 1.0;
 | |
|         var mediaEl  = ge1('.grouped_media', thumbEl);
 | |
|         var helperEl = ge1('.grouped_media_helper', thumbEl);
 | |
| 
 | |
|         if (mediaEl) {
 | |
|           var media_height = Math.ceil(width / ratio);
 | |
|           var media_tb = height - media_height;
 | |
|           if (media_tb < 0) {
 | |
|             var media_t = Math.floor(media_tb / 2);
 | |
|             var media_b = media_tb - media_t;
 | |
|             mediaEl.style.left = 0;
 | |
|             mediaEl.style.right = 0;
 | |
|             mediaEl.style.top = media_t + 'px';
 | |
|             mediaEl.style.bottom = media_b + 'px';
 | |
|           } else {
 | |
|             var media_width = Math.ceil(height * ratio);
 | |
|             var media_lr = width - media_width;
 | |
|             var media_l = Math.floor(media_lr / 2);
 | |
|             var media_r = media_lr - media_l;
 | |
|             mediaEl.style.top = 0;
 | |
|             mediaEl.style.bottom = 0;
 | |
|             mediaEl.style.left = media_l + 'px';
 | |
|             mediaEl.style.right = media_r + 'px';
 | |
|           }
 | |
|         }
 | |
|         if (helperEl) {
 | |
|           var helper_height = Math.floor(th_width / ratio);
 | |
|           var helper_tb = th_height - helper_height;
 | |
|           if (helper_tb > 0) {
 | |
|             var helper_t = Math.floor(helper_tb / 2);
 | |
|             var helper_b = helper_tb - helper_t;
 | |
|             helperEl.style.left = 0;
 | |
|             helperEl.style.right = 0;
 | |
|             helperEl.style.top = helper_t + 'px';
 | |
|             helperEl.style.bottom = helper_b + 'px';
 | |
|           } else {
 | |
|             var helper_width = Math.ceil(th_height * ratio);
 | |
|             var helper_lr = th_width - helper_width;
 | |
|             var helper_l = Math.floor(helper_lr / 2);
 | |
|             var helper_r = helper_lr - helper_l;
 | |
|             helperEl.style.top = 0;
 | |
|             helperEl.style.bottom = 0;
 | |
|             helperEl.style.left = helper_l + 'px';
 | |
|             helperEl.style.right = helper_r + 'px';
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       function recalcGrouped(max_w) {
 | |
|         var orients = '';
 | |
|         var ratios = [];
 | |
|         var cnt = thumbsEl.length;
 | |
| 
 | |
|         var ratios_sum = 0;
 | |
|         for (var i = 0; i < thumbsEl.length; i++) {
 | |
|           var thumbEl = thumbsEl[i];
 | |
|           var ratio = +thumbEl.getAttribute('data-ratio') || 1.0;
 | |
|           orients += ratio > 1.2 ? 'w' : (ratio < 0.8 ? 'n' : 'q');
 | |
|           ratios_sum += ratio;
 | |
|           ratios.push(ratio);
 | |
|         }
 | |
| 
 | |
|         var avg_ratio = ratios.length ? ratios_sum / ratios.length : 1.0;
 | |
|         var max_ratio = 0.75;
 | |
|         var min_w     = 75;
 | |
|         var max_h     = max_w / max_ratio;
 | |
| 
 | |
|         var w, h, w0, w1, w2, h0, h1, h2, x, y, x1, x2, y1, y2,
 | |
|             th_width, th_height;
 | |
| 
 | |
|         if (cnt == 2) {
 | |
|           if (orients == 'ww' &&
 | |
|               avg_ratio > 1.4 * max_ratio &&
 | |
|               (ratios[1] - ratios[0]) < 0.2) {
 | |
|             // 2 wide pics are one below the other
 | |
|             w = max_w;
 | |
|             h = Math.min(w / ratios[0], Math.min(w / ratios[1], (max_h - margin_h) / 2.0));
 | |
|             th_width  = max_w;
 | |
|             th_height = 2 * h + margin_h;
 | |
|             h0 = Math.floor(h);
 | |
|             h1 = th_height - h0 - margin_h;
 | |
|             y = h0 + margin_h;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w, h0, th_width, th_height, 'trl');
 | |
|             updateThumb(thumbsEl[1], 0, y, w, h1, th_width, th_height, 'rbl');
 | |
|           }
 | |
|           else if (orients == 'ww' || orients == 'qq') {
 | |
|             // 2 equal width pics
 | |
|             w = (max_w - margin_w) / 2;
 | |
|             h = Math.floor(Math.min(max_h, Math.min(w / ratios[0], w / ratios[1])));
 | |
|             th_width  = max_w;
 | |
|             th_height = h;
 | |
|             w0 = Math.floor(w);
 | |
|             w1 = max_w - w0 - margin_w;
 | |
|             x = w0 + margin_w;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w0, h, th_width, th_height, 'tbl');
 | |
|             updateThumb(thumbsEl[1], x, 0, w1, h, th_width, th_height, 'trb');
 | |
|           }
 | |
|           else {
 | |
|             // so, we have one wide and one not wide (square or narrow)
 | |
|             w0 = Math.floor((max_w - margin_w) / ratios[1] / (1 / ratios[0] + 1 / ratios[1]));
 | |
|             w1 = max_w - w0 - margin_w;
 | |
|             h = Math.floor(Math.min(max_h, Math.min(w0 / ratios[0], w1 / ratios[1])));
 | |
|             th_width  = max_w;
 | |
|             th_height = h;
 | |
|             x = w0 + margin_w;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w0, h, th_width, th_height, 'tbl');
 | |
|             updateThumb(thumbsEl[1], x, 0, w1, h, th_width, th_height, 'trb');
 | |
|           }
 | |
|         }
 | |
|         else if (cnt == 3) {
 | |
|           if (orients[0] == 'n') {
 | |
|             // 2nd and 3rd photos are on the right part
 | |
|             h0 = max_h;
 | |
|             h2 = Math.floor(Math.min((max_h - margin_h) * 0.5, ratios[1] * (max_h - margin_h) / (ratios[2] + ratios[1])));
 | |
|             h1 = max_h - h2 - margin_h;
 | |
|             w1 = Math.floor(Math.max(min_w, Math.min((max_w - margin_w) * 0.5, Math.min(h2 * ratios[2], h1 * ratios[1]))));
 | |
|             w0 = Math.min(Math.floor(h0 * ratios[0]), (max_w - w1 - margin_w));
 | |
|             th_width  = w0 + w1 + margin_w;
 | |
|             th_height = max_h;
 | |
|             x = w0 + margin_w;
 | |
|             y = h1 + margin_h;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w0, h0, th_width, th_height, 'tbl');
 | |
|             updateThumb(thumbsEl[1], x, 0, w1, h1, th_width, th_height, 'tr');
 | |
|             updateThumb(thumbsEl[2], x, y, w1, h2, th_width, th_height, 'rb');
 | |
|           }
 | |
|           else {
 | |
|             // 2nd and 3rd photos are on the next line
 | |
|             w0 = max_w;
 | |
|             h0 = Math.floor(Math.min(w0 / ratios[0], (max_h - margin_h) * 0.66));
 | |
|             w = (max_w - margin_w) / 2;
 | |
|             h = Math.floor(Math.min(max_h - h0 - margin_h, Math.min(w / ratios[1], w / ratios[2])));
 | |
|             th_width  = max_w;
 | |
|             th_height = h0 + h + margin_h;
 | |
|             w1 = Math.floor(w);
 | |
|             w2 = max_w - w1 - margin_w;
 | |
|             x = w1 + margin_w;
 | |
|             y = h0 + margin_h;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w0, h0, th_width, th_height, 'tlr');
 | |
|             updateThumb(thumbsEl[1], 0, y, w1, h, th_width, th_height, 'bl');
 | |
|             updateThumb(thumbsEl[2], x, y, w2, h, th_width, th_height, 'rb');
 | |
|           }
 | |
|         }
 | |
|         else if (cnt == 4) {
 | |
|           if (orients == 'wwww' || orients[0] == 'w') {
 | |
|             // 2nd, 3rd and 4th photos are on the next line
 | |
|             w = max_w;
 | |
|             h0 = Math.floor(Math.min(w / ratios[0], (max_h - margin_h) * 0.66));
 | |
|             h = (max_w - 2 * margin_w) / (ratios[1] + ratios[2] + ratios[3]);
 | |
|             w0 = Math.floor(Math.max(min_w, Math.min((max_w - 2 * margin_w) * 0.4, h * ratios[1])));
 | |
|             w2 = Math.floor(Math.max(min_w, Math.min((max_w - 2 * margin_w) * 0.33, h * ratios[3])));
 | |
|             w1 = w - w0 - w2 - 2 * margin_w;
 | |
|             h = Math.floor(Math.min(max_h - h0 - margin_h, h));
 | |
|             th_width  = max_w;
 | |
|             th_height = h0 + h + margin_h;
 | |
|             y = h0 + margin_h;
 | |
|             x1 = w0 + margin_w;
 | |
|             x2 = x1 + w1 + margin_w;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w, h0, th_width, th_height, 'tlr');
 | |
|             updateThumb(thumbsEl[1], 0, y, w0, h, th_width, th_height, 'bl');
 | |
|             updateThumb(thumbsEl[2], x1, y, w1, h, th_width, th_height, 'b');
 | |
|             updateThumb(thumbsEl[3], x2, y, w2, h, th_width, th_height, 'rb');
 | |
|           }
 | |
|           else {
 | |
|             // 2nd, 3rd and 4th photos are on the right part
 | |
|             h = max_h;
 | |
|             w0 = Math.floor(Math.min(h * ratios[0], (max_w - margin_w) * 0.66));
 | |
|             w = Math.floor((max_h - 2 * margin_h) / (1 / ratios[1] + 1 / ratios[2] + 1 / ratios[3]));
 | |
|             h0 = Math.floor(w / ratios[1]);
 | |
|             h2 = Math.floor(w / ratios[3]);
 | |
|             h1 = h - h0 - h2 - 2 * margin_h;
 | |
|             w = Math.max(min_w, Math.min(max_w - w0 - margin_w, w));
 | |
|             th_width  = w0 + w + margin_w;
 | |
|             th_height = max_h;
 | |
|             x = w0 + margin_w;
 | |
|             y1 = h0 + margin_h;
 | |
|             y2 = y1 + h1 + margin_h;
 | |
|             updateThumb(thumbsEl[0], 0, 0, w0, h, th_width, th_height, 'tbl');
 | |
|             updateThumb(thumbsEl[1], x, 0, w, h0, th_width, th_height, 'tr');
 | |
|             updateThumb(thumbsEl[2], x, y1, w, h1, th_width, th_height, 'r');
 | |
|             updateThumb(thumbsEl[3], x, y2, w, h2, th_width, th_height, 'rb');
 | |
|           }
 | |
|         }
 | |
|         else {
 | |
|           var ratios_cropped = [];
 | |
|           for (var i = 0; i < ratios.length; i++) {
 | |
|             var ratio = ratios[i];
 | |
|             if (avg_ratio > 1.1) {
 | |
|               ratio_cropped = Math.max(1.0, ratio);
 | |
|             } else {
 | |
|               ratio_cropped = Math.min(1.0, ratio);
 | |
|             }
 | |
|             ratio_cropped = Math.max(0.66667, Math.min(1.7, ratio_cropped));
 | |
|             ratios_cropped.push(ratio_cropped);
 | |
|           }
 | |
| 
 | |
|           var multiHeight = function(ratios) {
 | |
|             var ratios_sum = 0;
 | |
|             for (var i = 0; i < ratios.length; i++) {
 | |
|               var ratio = ratios[i];
 | |
|               ratios_sum += ratio;
 | |
|             }
 | |
|             return (max_w - (ratios.length - 1) * margin_w) / ratios_sum;
 | |
|           };
 | |
| 
 | |
|           var tries = [];
 | |
|           var first_line, second_line, third_line, fourth_line;
 | |
|           // Two lines
 | |
|           for (first_line = 1; first_line <= cnt - 1; first_line++) {
 | |
|             second_line = cnt - first_line;
 | |
|             if (first_line  > 3 ||
 | |
|                 second_line > 3) {
 | |
|               continue;
 | |
|             }
 | |
|             tries.push([[first_line, second_line], [
 | |
|               multiHeight(ratios_cropped.slice(0, first_line)),
 | |
|               multiHeight(ratios_cropped.slice(first_line)),
 | |
|             ]]);
 | |
|           }
 | |
| 
 | |
|           // Three lines
 | |
|           for (first_line = 1; first_line <= cnt - 2; first_line++) {
 | |
|             for (second_line = 1; second_line <= cnt - first_line - 1; second_line++) {
 | |
|               third_line = cnt - first_line - second_line;
 | |
|               if (first_line  > 3 ||
 | |
|                   second_line > (avg_ratio < 0.85 ? 4 : 3) ||
 | |
|                   third_line  > 3) {
 | |
|                 continue;
 | |
|               }
 | |
|               tries.push([[first_line, second_line, third_line], [
 | |
|                 multiHeight(ratios_cropped.slice(0, first_line)),
 | |
|                 multiHeight(ratios_cropped.slice(first_line, first_line + second_line)),
 | |
|                 multiHeight(ratios_cropped.slice(first_line + second_line)),
 | |
|               ]]);
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           // Four lines
 | |
|           for (first_line = 1; first_line <= cnt - 3; first_line++) {
 | |
|             for (second_line = 1; second_line <= cnt - first_line - 2; second_line++) {
 | |
|               for (third_line = 1; third_line <= cnt - first_line - second_line - 1; third_line++) {
 | |
|                 fourth_line = cnt - first_line - second_line - third_line;
 | |
|                 if (first_line  > 3 ||
 | |
|                     second_line > 3 ||
 | |
|                     third_line  > 3 ||
 | |
|                     fourth_line > 3) {
 | |
|                   continue;
 | |
|                 }
 | |
|                 tries.push([[first_line, second_line, third_line, fourth_line], [
 | |
|                   multiHeight(ratios_cropped.slice(0, first_line)),
 | |
|                   multiHeight(ratios_cropped.slice(first_line, first_line + second_line)),
 | |
|                   multiHeight(ratios_cropped.slice(first_line + second_line, first_line + second_line + third_line)),
 | |
|                   multiHeight(ratios_cropped.slice(first_line + second_line + third_line)),
 | |
|                 ]]);
 | |
|               }
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           // Looking for minimum difference between thumbs block height and max_h (may probably be little over)
 | |
|           var opt_i = false;
 | |
|           var opt_conf = false;
 | |
|           var opt_diff = false;
 | |
|           var opt_h = false;
 | |
|           for (var i = 0; i < tries.length; i++) {
 | |
|             var conf_nums = tries[i][0];
 | |
|             var heights = tries[i][1];
 | |
|             var heights_sum = 0;
 | |
|             var heights_min = Infinity;
 | |
|             for (var j = 0; j < heights.length; j++) {
 | |
|               heights_sum += heights[j];
 | |
|               if (heights_min > heights[j]) {
 | |
|                 heights_min = heights[j];
 | |
|               }
 | |
|             }
 | |
|             var conf_h = Math.floor(heights_sum + margin_h * (heights.length - 1));
 | |
|             var conf_diff = Math.abs(conf_h - max_h);
 | |
|             if (conf_nums.length > 1) {
 | |
|               if (conf_nums[0] > conf_nums[1] ||
 | |
|                   conf_nums[2] && conf_nums[1] > conf_nums[2] ||
 | |
|                   conf_nums[3] && conf_nums[2] > conf_nums[3]) {
 | |
|                 conf_diff *= 1.5;
 | |
|               }
 | |
|             }
 | |
|             if (heights_min < min_w) {
 | |
|               conf_diff *= 1.5;
 | |
|             }
 | |
|             if (opt_conf === false || conf_diff < opt_diff) {
 | |
|               opt_i = i;
 | |
|               opt_conf = cloneArr(conf_nums);
 | |
|               opt_diff = conf_diff;
 | |
|               opt_h = conf_h;
 | |
|             }
 | |
|           }
 | |
| 
 | |
|           // Generating optimal thumbs
 | |
|           th_width  = max_w;
 | |
|           th_height = opt_h;
 | |
|           var thumbs_remain = cloneArr(thumbsEl);
 | |
|           var ratios_remain = cloneArr(ratios_cropped);
 | |
|           var chunks = cloneArr(opt_conf);
 | |
|           var opt_heights = cloneArr(tries[opt_i][1]);
 | |
|           var chunks_num = chunks.length;
 | |
|           var last_row = chunks_num - 1;
 | |
|           var sy = 0;
 | |
|           for (var i = 0; i < chunks.length; i++) {
 | |
|             var line_chunks_num = chunks[i];
 | |
|             var line_thumbs = thumbs_remain.splice(0, line_chunks_num);
 | |
|             var line_height = opt_heights.shift();
 | |
|             var last_column = line_thumbs.length - 1;
 | |
|             var h = Math.floor(line_height);
 | |
|             var sx = 0;
 | |
|             var t = '', r = '', b = '', l = '';
 | |
|             if (i == 0) {
 | |
|               t = 't';
 | |
|             }
 | |
|             if (i == last_row) {
 | |
|               b = 'b';
 | |
|               h = th_height - sy;
 | |
|             }
 | |
|             for (var j = 0; j < line_thumbs.length; j++) {
 | |
|               var thumbEl = line_thumbs[j];
 | |
|               var thumb_ratio = ratios_remain.shift();
 | |
|               var w = Math.floor(thumb_ratio * h);
 | |
|               if (j == 0) {
 | |
|                 l = 'l';
 | |
|               }
 | |
|               if (j == last_column) {
 | |
|                 r = 'r';
 | |
|                 w = th_width - sx;
 | |
|               }
 | |
|               updateThumb(thumbEl, sx, sy, w, h, th_width, th_height, t+r+b+l);
 | |
|               sx += w + margin_w;
 | |
|             }
 | |
|             sy += h + margin_h;
 | |
|           }
 | |
|         }
 | |
| 
 | |
|         groupedEl.style.paddingTop  = (th_height / th_width * 100) + '%';
 | |
|         groupedLayerEl.style.width  = th_width + 'px';
 | |
|         groupedLayerEl.style.height = th_height + 'px';
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TRoundVideo = window.TRoundVideo = {
 | |
|     init: function(playerEl) {
 | |
|       playerEl = geById(playerEl);
 | |
|       if (!playerEl || playerEl.__inited) return;
 | |
|       playerEl.__inited = true;
 | |
|       var videoEl = ge1('.js-message_roundvideo', playerEl)
 | |
|         , playEl = ge1('.js-message_roundvideo_play', playerEl)
 | |
|         , progressEl = ge1('.js-message_roundvideo_progress', playerEl)
 | |
|         , durationEl = ge1('.js-message_roundvideo_duration', playerEl)
 | |
|         , playing = false;
 | |
|       if (!videoEl) return;
 | |
| 
 | |
|       function autoplay() {
 | |
|         if (!videoEl) return;
 | |
|         removeEvent(document, 'touchstart', autoplay);
 | |
|         removeClass(playerEl, 'playing');
 | |
|         playing = false;
 | |
|         videoEl.muted = true;
 | |
|         videoEl.loop = true;
 | |
|         videoEl.currentTime = 0;
 | |
|         play();
 | |
|         showProgress();
 | |
|       }
 | |
|       function showProgress() {
 | |
|         if (!videoEl) return;
 | |
|         if (playing && !videoEl.paused) {
 | |
|           requestAnimationFrame(function(){ showProgress(); });
 | |
|         }
 | |
|         redrawProgress();
 | |
|         if (videoEl.duration) {
 | |
|           var duration = Math.floor(videoEl.duration);
 | |
|           durationEl.innerHTML = formatDuration(duration - videoEl.currentTime);
 | |
|         }
 | |
|       }
 | |
|       function redrawProgress(updateSVG) {
 | |
|         if (!videoEl) return;
 | |
|         var progress;
 | |
|         if (playing) {
 | |
|           progress = videoEl.currentTime / videoEl.duration;
 | |
|         } else {
 | |
|           progress = 0;
 | |
|         }
 | |
|         progress = Math.max(0, Math.min(progress, 1));
 | |
|         var wrapWidth = playerEl.offsetWidth;
 | |
|         if (wrapWidth) {
 | |
|           var rd = progressEl.getAttribute('data-rd') || 3;
 | |
|           var d = (wrapWidth - rd);
 | |
|           var l = (d * Math.PI);
 | |
|           progressEl.setAttribute('r', (d / 2));
 | |
|           progressEl.setAttribute('stroke-dasharray', l);
 | |
|           progressEl.setAttribute('stroke-dashoffset', l * (1 - progress));
 | |
|           if (updateSVG) {
 | |
|             progressEl.style.transform = !progressEl.style.transform ? 'rotateZ(270deg)' : '';
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       function play() {
 | |
|         if (!videoEl) return;
 | |
|         var video = videoEl;
 | |
|         var isPlaying = (video.currentTime > 0) &&
 | |
|                         !video.paused &&
 | |
|                         !video.ended &&
 | |
|                         (video.readyState > 2);
 | |
|         if (!isPlaying) {
 | |
|           video.play();
 | |
|           if (playing) {
 | |
|             triggerEvent(videoEl, 'tg:play', {bubbles: true});
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       addEvent(document, 'tg:play', function(e) {
 | |
|         if (e.target === videoEl || !playing) return true;
 | |
|         if (videoEl.paused) {
 | |
|           play();
 | |
|           showProgress();
 | |
|         } else {
 | |
|           autoplay();
 | |
|         }
 | |
|       });
 | |
|       function pause() {
 | |
|         if (!videoEl) return;
 | |
|         videoEl.pause();
 | |
|       }
 | |
|       function toggle(e) {
 | |
|         e.stopPropagation();
 | |
|         if (!playing) {
 | |
|           redrawProgress();
 | |
|           addClass(playerEl, 'playing');
 | |
|           playing = true;
 | |
|           videoEl.muted = false;
 | |
|           videoEl.loop = false;
 | |
|           videoEl.currentTime = 0;
 | |
|           play();
 | |
|           showProgress();
 | |
|         } else {
 | |
|           if (videoEl.paused) {
 | |
|             play();
 | |
|             showProgress();
 | |
|           } else {
 | |
|             pause();
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       enableInlineVideo(videoEl);
 | |
| 
 | |
|       checkVideo(videoEl, function() {
 | |
|         addClass(playerEl, 'not_supported');
 | |
|       });
 | |
|       autoplay();
 | |
|       addEvent(document, 'touchstart', autoplay);
 | |
|       addEvent(videoEl, 'ended', function() {
 | |
|         autoplay();
 | |
|       });
 | |
|       addEvent(window, 'resize', function() {
 | |
|         redrawProgress(true)
 | |
|       });
 | |
|       if (playEl) {
 | |
|         addEvent(playEl, 'click', toggle);
 | |
|       }
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TVoice = window.TVoice = {
 | |
|     init: function(playerEl) {
 | |
|       playerEl = geById(playerEl);
 | |
|       if (!playerEl || playerEl.__inited) return;
 | |
|       playerEl.__inited = true;
 | |
|       var audioEl = ge1('.js-message_voice', playerEl)
 | |
|         , durationEl = ge1('.js-message_voice_duration', playerEl)
 | |
|         , progressEl = ge1('.js-message_voice_progress', playerEl)
 | |
|         , progressWrapEl = ge1('.js-message_voice_progress_wrap', playerEl)
 | |
|         , player = null
 | |
|         , isOGG = audioEl.hasAttribute('data-ogg')
 | |
|         , seekTo = null
 | |
|         , seeking = false
 | |
|         , disableClick = false;
 | |
|       if (!audioEl) return;
 | |
| 
 | |
|       function initPlayer() {
 | |
|         addClass(playerEl, 'ready');
 | |
|         addEvent(player, 'play', function() {
 | |
|           addClass(playerEl, 'playing');
 | |
|           triggerEvent(playerEl, 'tg:play', {bubbles: true});
 | |
|         });
 | |
|         addEvent(player, 'pause', function() {
 | |
|           removeClass(playerEl, 'playing');
 | |
|         });
 | |
|         addEvent(player, 'ended', function() {
 | |
|           player.currentTime = 0;
 | |
|           showProgress();
 | |
|         });
 | |
|         addEvent(player, 'loadedmetadata', function() {
 | |
|           showProgress();
 | |
|         });
 | |
|         addEvent(playerEl, 'click', toggle);
 | |
|         addEvent(progressWrapEl, 'mousedown touchstart', seekStart);
 | |
|         addEvent(document, 'tg:play', stop);
 | |
|       }
 | |
|       function toggle(e) {
 | |
|         e.stopPropagation();
 | |
|         if (!disableClick) {
 | |
|           if (!player) return true;
 | |
|           if (player.paused) {
 | |
|             player.play();
 | |
|             showProgress();
 | |
|           } else {
 | |
|             player.pause();
 | |
|             showProgress();
 | |
|           }
 | |
|         } else {
 | |
|           disableClick = false;
 | |
|         }
 | |
|         e.preventDefault();
 | |
|         return false;
 | |
|       }
 | |
|       function stop(e) {
 | |
|         if (e.target === playerEl || !player) return true;
 | |
|         if (!player.paused) {
 | |
|           player.pause();
 | |
|           showProgress();
 | |
|         }
 | |
|         return false;
 | |
|       }
 | |
|       function seekStart(e) {
 | |
|         if (player &&
 | |
|             player.duration !== Infinity &&
 | |
|             (!player.paused ||
 | |
|              player.currentTime > 0 && player.currentTime < player.duration)) {
 | |
|           e.preventDefault();
 | |
|           seeking = true;
 | |
|           disableClick = false;
 | |
|           player.pause();
 | |
|           addEvent(document, 'mousemove touchmove', seek);
 | |
|           addEvent(document, 'mouseup mouseleave touchend touchcancel', seekEnd);
 | |
|           seek(e);
 | |
|         }
 | |
|       }
 | |
|       function seek(e) {
 | |
|         if (!seeking) return;
 | |
|         var px = e.pageX;
 | |
|         var op = progressWrapEl;
 | |
|         var x = op.offsetLeft;
 | |
|         var w = op.offsetWidth;
 | |
|         while (op = op.offsetParent) {
 | |
|           x += op.offsetLeft;
 | |
|         }
 | |
|         var ct = Math.max(0, Math.min(px - x, w)) / w;
 | |
|         seekTo = ct;
 | |
|         showProgress();
 | |
|       }
 | |
|       function seekEnd(e) {
 | |
|         if (!seeking) return;
 | |
|         seek(e);
 | |
|         var duration = Math.floor(player.duration);
 | |
|         player.currentTime = seekTo * duration;
 | |
|         seekTo = null;
 | |
|         seeking = false;
 | |
|         if (e.type.substr(0, 5) == 'mouse') {
 | |
|           disableClick = true;
 | |
|         }
 | |
|         player.play();
 | |
|         showProgress();
 | |
|         removeEvent(document, 'mousemove touchmove', seek);
 | |
|         removeEvent(document, 'mouseup touchend', seekEnd);
 | |
|       }
 | |
|       function showProgress() {
 | |
|         if (!player) return;
 | |
|         if (!player.paused) {
 | |
|           requestAnimationFrame(function(){ showProgress(); });
 | |
|         }
 | |
|         if (player.duration && player.duration !== Infinity) {
 | |
|           var duration = Math.floor(player.duration);
 | |
|           if (seeking) {
 | |
|             var currentTime = seekTo * duration;
 | |
|           } else {
 | |
|             var currentTime = Math.max(0, player.currentTime);
 | |
|           }
 | |
|           if (progressEl) {
 | |
|             progressEl.style.width = Math.min(100, currentTime / duration * 100) + '%';
 | |
|           }
 | |
|           if (durationEl) {
 | |
|             durationEl.innerHTML = formatDuration(duration - currentTime);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|       function redrawProgress() {
 | |
|         if (!audioEl) return;
 | |
|         var ss = progressWrapEl.getElementsByTagName('S');
 | |
|         var ss_count = ss.length / 2;
 | |
|         var waveform_str = audioEl.getAttribute('data-waveform') || '';
 | |
|         var waveform = waveform_str.split(',');
 | |
|         var lines_cnt = Math.floor((progressWrapEl.offsetWidth + 2) / 6);
 | |
|         var p = waveform.length / lines_cnt;
 | |
|         var values = [];
 | |
|         var max_value = 0;
 | |
|         for (var i = 0; i < lines_cnt; i++) {
 | |
|           var ws = i * p;
 | |
|           var we = ws + p;
 | |
|           var wsi = Math.floor(ws);
 | |
|           var wei = Math.floor(we);
 | |
|           if (wsi == wei) {
 | |
|             var value = waveform[wsi] * (we - ws);
 | |
|           } else {
 | |
|             var value = 0;
 | |
|             for (var j = wsi; j <= wei; j++) {
 | |
|               var wv = +waveform[j] || 0;
 | |
|               if (j == wsi) {
 | |
|                 value += wv * (j + 1 - ws);
 | |
|               } else if (j == wei) {
 | |
|                 value += wv * (we - j);
 | |
|               } else {
 | |
|                 value += wv;
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|           value = value / p;
 | |
|           max_value = Math.max(value, max_value);
 | |
|           values.push(value);
 | |
|         }
 | |
|         for (var i = 0; i < ss.length; i++) {
 | |
|           var li = i % ss_count;
 | |
|           if (li < lines_cnt) {
 | |
|             var height = (values[li] / max_value) * 100;
 | |
|             ss[i].style.height = height + '%';
 | |
|             ss[i].style.display = '';
 | |
|           } else {
 | |
|             ss[i].style.display = 'none';
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       loadLib('js/ogvjs/ogv-support.js', function(success) {
 | |
|         if (!success) return;
 | |
|         if (isOGG &&
 | |
|             OGVCompat.hasWebAudio() &&
 | |
|             OGVCompat.supported('OGVPlayer')) {
 | |
|           loadLib('js/ogvjs/ogv.js', function(success) {
 | |
|             if (!success) return;
 | |
|             player = new OGVPlayer();
 | |
|             player.src = audioEl.src;
 | |
|             initPlayer();
 | |
|           });
 | |
|         } else {
 | |
|           player = audioEl;
 | |
|           initPlayer();
 | |
|         }
 | |
|       });
 | |
|       addEvent(window, 'resize', function(){ redrawProgress() });
 | |
|       redrawProgress();
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TSticker = window.TSticker = {
 | |
|     init: proccessWebpImage
 | |
|   };
 | |
| 
 | |
|   var TVideoSticker = window.TVideoSticker = {
 | |
|     init: proccessWebmImage
 | |
|   };
 | |
| 
 | |
|   var TEmoji = window.TEmoji = {
 | |
|     init: proccessEmoji
 | |
|   }
 | |
| 
 | |
|   window.TWidgetPost = {
 | |
|     init: function(options) {
 | |
|       if (!doesSupportEmoji()) {
 | |
|         removeClass(document.body, 'emoji_default');
 | |
|         addClass(document.body, 'emoji_image');
 | |
|       }
 | |
|       options = options || {};
 | |
|       TWidgetPost.options = options;
 | |
| 
 | |
|       gec('.js-widget_message', function() {
 | |
|         TPost.init(this, {tgs_workers_limit: 1});
 | |
|         addEvent(ge('.js-poll_option', this), 'click', TWidgetPost.eSelectPollOption);
 | |
|         addEvent(ge('.js-poll_vote_btn', this), 'click', TWidgetPost.eSendVotes);
 | |
|       });
 | |
|       initWidgetFrame({
 | |
|         auto_height: true,
 | |
|         onVisible: function() {
 | |
|           gec('.js-widget_message', function() {
 | |
|             TPost.view(this);
 | |
|           });
 | |
|         }
 | |
|       });
 | |
|       addEvent(window, 'tg:optionschange', TWidgetPost.onOptionsChange);
 | |
|     },
 | |
|     onOptionsChange: function(e) {
 | |
|       var new_options = e.detail, transition_off = false;
 | |
|       if (typeof new_options.dark !== undefined) {
 | |
|         transition_off = true;
 | |
|         addClass(document.body, 'no_transitions');
 | |
|         toggleClass(document.body, 'dark', !!new_options.dark);
 | |
|         toggleClass(document.body, 'nodark', !new_options.dark);
 | |
|         var root = document.documentElement;
 | |
|         if (root && root.style) {
 | |
|           root.style.colorScheme = !new_options.dark ? 'light' : 'dark';
 | |
|         }
 | |
|       }
 | |
|       if (transition_off) {
 | |
|         setTimeout(function() {
 | |
|           removeClass(document.body, 'no_transitions');
 | |
|         }, 100);
 | |
|       }
 | |
|     },
 | |
|     eSelectPollOption: function(e) {
 | |
|       e.preventDefault();
 | |
|       if (!TWidgetAuth.isLoggedIn()) {
 | |
|         return TWidgetAuth.logIn();
 | |
|       }
 | |
|       var poll_el = gpeByClass(this, 'js-poll');
 | |
|       if (!poll_el) {
 | |
|         return false;
 | |
|       }
 | |
|       toggleClass(this, 'selected');
 | |
|       toggleClass(poll_el, 'selected', ge('.js-poll_option.selected', poll_el).length > 0);
 | |
|       if (!hasClass(poll_el, 'multiple')) {
 | |
|         TWidgetPost.sendPollVote(poll_el, this);
 | |
|       }
 | |
|     },
 | |
|     eSendVotes: function(e) {
 | |
|       e.preventDefault();
 | |
|       if (!TWidgetAuth.isLoggedIn()) {
 | |
|         return TWidgetAuth.logIn();
 | |
|       }
 | |
|       var poll_el = gpeByClass(this, 'js-poll');
 | |
|       if (!poll_el) {
 | |
|         return false;
 | |
|       }
 | |
|       TWidgetPost.sendPollVote(poll_el, this);
 | |
|     },
 | |
|     sendPollVote: function(poll_el, option_el) {
 | |
|       if (!poll_el || hasClass(poll_el, 'sending')) {
 | |
|         return false;
 | |
|       }
 | |
|       var option_els = ge('.js-poll_option.selected', poll_el);
 | |
|       var options = TWidgetPost.options || {};
 | |
|       var post_el = gpeByClass(option_el, 'js-widget_message');
 | |
|       if (!post_el) {
 | |
|         return false;
 | |
|       }
 | |
|       var peer = getAttr(post_el, 'data-peer');
 | |
|       var peer_hash = getAttr(post_el, 'data-peer-hash');
 | |
|       var post_id = getAttr(post_el, 'data-post-id');
 | |
|       if (!peer || !peer_hash || !post_id) {
 | |
|         return false;
 | |
|       }
 | |
|       var poll_options = [];
 | |
|       gec(option_els, function() {
 | |
|         poll_options.push(getAttr(this, 'data-value'));
 | |
|       });
 | |
|       removeClass(poll_el, 'selected');
 | |
|       addClass(poll_el, 'sending');
 | |
|       apiRequest('sendVote', {
 | |
|         peer: peer,
 | |
|         peer_hash: peer_hash,
 | |
|         post_id: post_id,
 | |
|         options: poll_options.join(';')
 | |
|       }, function(err, result) {
 | |
|         removeClass(poll_el, 'sending');
 | |
|         if (result.media_html) {
 | |
|           var media_wrap = newEl('div', '', result.media_html);
 | |
|           var media_html = getHtml('.js-poll', media_wrap);
 | |
|           setHtml(poll_el, media_html);
 | |
|           addEvent(ge('.js-poll_option', poll_el), 'click', TWidgetPost.eSelectPollOption);
 | |
|           addEvent(ge('.js-poll_vote_btn', poll_el), 'click', TWidgetPost.eSendVotes);
 | |
|         }
 | |
|         toggleClass(poll_el, 'selected', ge('.js-poll_option.selected', poll_el).length > 0);
 | |
|       });
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   var TWidgetLogin = {
 | |
|     init: function(id, bot_id, params, init_auth) {
 | |
|       initWidgetFrame({
 | |
|         auto_height: true,
 | |
|         auto_width: true
 | |
|       });
 | |
|       TWidgetLogin.widgetEl = document.getElementById(id);
 | |
|       TWidgetLogin.botId = bot_id;
 | |
|       TWidgetLogin.params = params;
 | |
|       TWidgetLogin.lang = (params || {}).lang;
 | |
|       var params_encoded = '', params_arr = [];
 | |
|       for (var k in params) {
 | |
|         params_arr.push(encodeURIComponent(k) + '=' + encodeURIComponent(params[k]));
 | |
|       }
 | |
|       TWidgetLogin.paramsEncoded = params_arr.join('&');
 | |
|       if (init_auth) {
 | |
|         TWidgetLogin.getAuth(true);
 | |
|       }
 | |
|       addEvent(window, 'message', function (event) {
 | |
|         try {
 | |
|           var data = JSON.parse(event.data);
 | |
|         } catch(e) {
 | |
|           var data = {};
 | |
|         }
 | |
|         if (event.source !== TWidgetLogin.activePopup) return;
 | |
|         if (data.event == 'auth_result') {
 | |
|           TWidgetLogin.onAuth(data.origin, data.result);
 | |
|         }
 | |
|       });
 | |
|     },
 | |
|     auth: function() {
 | |
|       var width = 550;
 | |
|       var height = 470;
 | |
|       var left = Math.max(0, (screen.width - width) / 2) + (screen.availLeft | 0),
 | |
|           top = Math.max(0, (screen.height - height) / 2) + (screen.availTop | 0);
 | |
|       function checkClose() {
 | |
|         if (!TWidgetLogin.activePopup || TWidgetLogin.activePopup.closed) {
 | |
|           return TWidgetLogin.onClose();
 | |
|         }
 | |
|         setTimeout(checkClose, 100);
 | |
|       }
 | |
|       TWidgetLogin.activePopup = window.open('/auth?bot_id=' + TWidgetLogin.botId + (TWidgetLogin.paramsEncoded ? '&' + TWidgetLogin.paramsEncoded : ''), 'telegram_oauth', 'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',status=0,location=0,menubar=0,toolbar=0');
 | |
|       TWidgetLogin.authFinished = false;
 | |
|       if (TWidgetLogin.activePopup) {
 | |
|         TWidgetLogin.activePopup.focus();
 | |
|         checkClose();
 | |
|       }
 | |
|     },
 | |
|     getAuth: function(init) {
 | |
|       var xhr = getXHR();
 | |
|       xhr.open('POST', '/auth/get?bot_id=' + TWidgetLogin.botId + (TWidgetLogin.lang ? '&lang=' + encodeURIComponent(TWidgetLogin.lang) : ''));
 | |
|       xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
 | |
|       xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
 | |
|       xhr.onreadystatechange = function() {
 | |
|         if (xhr.readyState == 4) {
 | |
|           if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
 | |
|             try {
 | |
|               var result = JSON.parse(xhr.responseText);
 | |
|             } catch(e) {
 | |
|               var result = {};
 | |
|             }
 | |
|             if (result.html && TWidgetLogin.widgetEl.innerHTML != result.html) {
 | |
|               TWidgetLogin.widgetEl.innerHTML = result.html;
 | |
|             }
 | |
|             if (result.user) {
 | |
|               TWidgetLogin.onAuth(result.origin, result.user, init);
 | |
|             } else {
 | |
|               TWidgetLogin.onAuth(result.origin, false, init);
 | |
|             }
 | |
|           } else {
 | |
|             TWidgetLogin.onAuth('*', false, init);
 | |
|           }
 | |
|         }
 | |
|       };
 | |
|       xhr.onerror = function() {
 | |
|         TWidgetLogin.onAuth('*', false, init);
 | |
|       };
 | |
|       xhr.withCredentials = true;
 | |
|       xhr.send(TWidgetLogin.paramsEncoded);
 | |
|     },
 | |
|     onAuth: function(origin, authData, init) {
 | |
|       if (TWidgetLogin.authFinished) return;
 | |
|       if (authData) {
 | |
|         var data = {event: 'auth_user', auth_data: authData};
 | |
|       } else {
 | |
|         var data = {event: 'unauthorized'};
 | |
|       }
 | |
|       if (init) {
 | |
|         data.init = true;
 | |
|       }
 | |
|       PostMessage.send(data, origin);
 | |
|       TWidgetLogin.authFinished = true;
 | |
|     },
 | |
|     onClose: function() {
 | |
|       TWidgetLogin.getAuth();
 | |
|     }
 | |
|   };
 | |
|   window.TWidgetLogin = TWidgetLogin;
 | |
| 
 | |
|   var TStats = {
 | |
|     init: function () {
 | |
|       if (!doesSupportEmoji()) {
 | |
|         removeClass(document.body, 'emoji_default');
 | |
|         addClass(document.body, 'emoji_image');
 | |
|       }
 | |
|       gec('.js-sticker_thumb', function() {
 | |
|         TSticker.init(this);
 | |
|       });
 | |
|     }
 | |
|   }
 | |
|   window.TStats = TStats;
 | |
| 
 | |
|   window.TWidget = {
 | |
|     initFrame: initWidgetFrame
 | |
|   };
 | |
| 
 | |
| })();
 |