Created
August 20, 2015 11:33
-
-
Save Bitaru/ddb4d970cbec5b34452e to your computer and use it in GitHub Desktop.
Iframe widgets initializer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require('currentscript') | |
| var EX = function(config){ | |
| this.config = this.prepareConfig(config); | |
| this.cache_bust = 1; | |
| this.iframe = this.create(this.config); | |
| this.subscribe(config.debug ? true : false); | |
| /** | |
| * Attach iframe node to window object in production mode | |
| * for easy access to those styles | |
| * And set excu object globaly for get/set events in debug | |
| */ | |
| if(typeof config.debug !== 'undefined'){ | |
| this.src = this.getCurrent().src | |
| return this | |
| } | |
| return this.iframe | |
| }; | |
| /** | |
| * Basic iframe constructor | |
| * @return {Object} Iframe NODE | |
| */ | |
| EX.prototype.create = function(opt){ | |
| // Create a buddy to get width | |
| var buddy, parent, | |
| script = this.getCurrent(), | |
| dimension = this.getDimensions(this.config); | |
| if(opt && opt.parent){ | |
| parent = typeof opt.parent == 'string' ? document.getElementById(opt.parent.replace('#', '')) : opt.parent; | |
| }else{ | |
| parent = script.parentElement; | |
| } | |
| if(typeof opt === 'undefined'){ | |
| buddy = document.createElement("div"); | |
| buddy.style.width = "100%"; | |
| buddy.style.height = "auto"; | |
| parent.insertBefore(buddy, script.nextSibling); | |
| }else{ | |
| buddy = parent; | |
| } | |
| var origin = this.getOrigin( opt && opt.src ? opt.src : script.src ), | |
| frameUrl = this.getFramePath(origin), | |
| iframe = document.createElement('iframe'); | |
| iframe.width = dimension.width; | |
| iframe.src = frameUrl+'#'+encodeURIComponent(document.location.href); | |
| iframe.frameBorder = 0; | |
| iframe.frameborder = 0; | |
| iframe.style.border = 'none'; | |
| iframe.marginheight = 0; | |
| iframe.marginwidth = 0; | |
| iframe.height = dimension.height; | |
| iframe.scrolling = 'no'; | |
| buddy.appendChild(iframe); | |
| return iframe; | |
| }; | |
| /** | |
| * Prepare config for support old version | |
| * @param {Object} Config object | |
| * @global {String} set excu.configString - | |
| * @return {Object} | |
| */ | |
| EX.prototype.prepareConfig = function prepare(config){ | |
| var out = {}, tmp = [], styles = []; | |
| for(var i in config){ | |
| var clean = i.replace('exc_', ''); | |
| if(typeof config[i] === 'string' && config[i].indexOf('%') !== -1){ | |
| continue | |
| } | |
| if(['query', 'q'].indexOf(clean) > -1 && config[i] === ''){ | |
| config[i] = document.title; | |
| } | |
| if(i === 'box_params' || i === 'style' || i === 'params'){ | |
| for(var p in config[i]){ | |
| if (config[i].hasOwnProperty(p)) { | |
| if(p === 'title' || p === 'query' || p === 'q'){ | |
| if(['query', 'q'].indexOf(p) > -1 && config[i][p] === ''){ | |
| config[i][p] = document.title; | |
| } | |
| tmp.push(p + '=' + this.encodeParamValue(config[i][p])); | |
| }else{ | |
| styles.push( p +'='+config[i][p]); | |
| } | |
| } | |
| } | |
| }else{ | |
| tmp.push(clean+'='+this.encodeParamValue(config[i])); | |
| } | |
| out[clean] = config[i]; | |
| } | |
| this.configString = '?'+tmp.join('&') + (styles.length > 0 ? '&style='+this.encodeParamValue(styles.join(';')) : ''); | |
| return out | |
| }; | |
| /** | |
| * Get origin of script/iframe | |
| * @params {String} Excusriopedia domain | |
| * @return {String} Origin | |
| */ | |
| EX.prototype.getOrigin = function(src){ | |
| var regex = /^(https?\:\/\/[^\/?#]+)(?:[\/?#]|$)/i, parts; | |
| if(src.indexOf(':3') == -1){ | |
| src = src.replace(/^http:\/\//i, 'https://'); | |
| } | |
| parts = src.match(regex); | |
| return parts && parts[1] | |
| }; | |
| /** | |
| * Return object of computed width and height for boxes | |
| * @params {Object} Widget config | |
| * @return {Object} Height|Width | |
| */ | |
| EX.prototype.getDimensions = function(config){ | |
| var isHeight = function () { return typeof config.height !== 'undefined'}, | |
| isWidth = function () { return typeof config.width !== 'undefined'}, | |
| compute; | |
| compute = function (height, width){ | |
| return { | |
| height: !isHeight() ? height : config.height, | |
| width: !isWidth() ? width : config.width | |
| } | |
| }; | |
| switch (config.type){ | |
| case 'box2': | |
| return compute('145px', '100%'); | |
| case 'box1': | |
| return compute('400px', '242px'); | |
| case 'category': | |
| return compute('690px', '900px'); | |
| case 'boxcustom': | |
| var params = config.box_params ? config.box_params : config.params | |
| return compute(params.height + 'px', params.width + 'px'); | |
| default: | |
| return compute('100%', '100%'); | |
| }; | |
| }; | |
| /** | |
| * Default iframe response aggregator for production mode | |
| * @params {Object} Response from iframe | |
| * @param {String} Additional option(default iframe hostname) | |
| */ | |
| EX.prototype.resizer = function(e){ | |
| var frame = (window.EX.iframe || window.EX); | |
| if (typeof e === 'object') { | |
| if(e.width){ | |
| frame.setAttribute('width', e.width + 'px'); | |
| } | |
| if(e.height){ | |
| frame.setAttribute('height', e.height + 'px'); | |
| } | |
| } | |
| }; | |
| /** | |
| * Return current script NODE | |
| * @return {Object} | |
| */ | |
| EX.prototype.getCurrent = function(){ | |
| var script; | |
| try { | |
| script = document.currentScript; | |
| script.src; | |
| }catch (e){ | |
| var stack = e.stack, | |
| scripts = document.getElementsByTagName("script"), | |
| src; | |
| if (!stack) | |
| return scripts[scripts.length - 1]; | |
| e = stack.indexOf(' at ') !== -1 ? ' at ' : '@'; | |
| while (stack.indexOf(e) !== -1) | |
| stack = stack.substring(stack.indexOf(e) + e.length); | |
| src = stack.substring(0, stack.indexOf(':', stack.indexOf(':')+1)); | |
| for(var i = 0; i < scripts.length; i++){ | |
| if(scripts[i].src === src){ | |
| script = scripts[i]; | |
| } | |
| } | |
| } | |
| return script; | |
| }; | |
| /** | |
| * Subscribe callbacks to message from iframe | |
| * @param {bool} | |
| */ | |
| EX.prototype.subscribe = function(debug){ | |
| // Attach event listener | |
| if(debug){ | |
| EX.prototype.set = function(data){ | |
| this.postMessage(data); | |
| if(typeof data.width !== 'undefined' || typeof data.height !== 'undefined'){ | |
| this.resizer(data); | |
| } | |
| return this | |
| }; | |
| EX.prototype.ready = function(callback){ | |
| this.getMessage(function(message){ | |
| if(message.ready && callback){ | |
| callback(this); | |
| } | |
| }); | |
| }; | |
| EX.prototype.reload = function(data){ | |
| var parent = this.iframe.parentNode, | |
| src = this.iframe.src; | |
| this.config = data; | |
| this.prepareConfig(data); | |
| removeElement(this.iframe); | |
| // Create new frame | |
| this.iframe = this.create({parent: parent, src: src}); | |
| return this | |
| }; | |
| }else{ | |
| var _self = this; | |
| this.getMessage(function(data){ | |
| _self.resizer.call(_self, data); | |
| }); | |
| } | |
| return this | |
| }; | |
| /** | |
| * Return path to widget | |
| * @param {string} Excurisopedia widget root | |
| */ | |
| EX.prototype.getFramePath = function(origin){ | |
| return origin + '/' + (this.config.lang || 'ru') + '/box/'+this.config.type + '/'+ this.configString; | |
| } | |
| /** | |
| * Excronize data for get Request | |
| * @param {string} Excurisopedia widget root | |
| */ | |
| EX.prototype.encodeParamValue = function(value) { | |
| if (typeof encodeURIComponent == "function") return encodeURIComponent(value); | |
| return escape(value); | |
| } | |
| /** | |
| * Send message to iframe | |
| * @param {Object} | |
| */ | |
| EX.prototype.postMessage = function(message) { | |
| var target = this.iframe || window.EX, | |
| target_url = target.src; | |
| if (window['postMessage']) { | |
| target.contentWindow['postMessage'](encodeJson(message), '*'); | |
| } else { | |
| target.location = target_url.replace(/#.*$/, '') + '#' + (+new Date) + (this.cache_bust++) + '&' + encodeJson(message); | |
| } | |
| }; | |
| /** | |
| * Get message from iframe | |
| * @return {Function} | |
| */ | |
| EX.prototype.getMessage = function(callback) { | |
| if (window['postMessage']) { | |
| if (callback) { | |
| var source_origin = this.getOrigin(this.iframe.src || EX.src) | |
| var attached_callback = function(e) { | |
| if ((typeof source_origin === 'string' && e.origin !== source_origin) | |
| || (Object.prototype.toString.call(source_origin) === "[object Function]" && source_origin(e.origin) === false)) { | |
| return !1; | |
| } | |
| callback(decodeJson(e.data)); | |
| }; | |
| } | |
| if (window['addEventListener']) { | |
| window[ callback ? 'addEventListener' : 'removeEventListener']('message', attached_callback, false); | |
| } else { | |
| window[callback ? 'attachEvent' : 'detachEvent']('onmessage', attached_callback); | |
| } | |
| } else { | |
| this.interval_id && clearInterval(this.interval_id); | |
| this.interval_id = null; | |
| var last_hash; | |
| if (callback) { | |
| last_hash = void 0; | |
| this.interval_id = setInterval((function(_this) { | |
| return function() { | |
| var hash, re; | |
| hash = document.location.hash; | |
| re = /^#?\d+&/; | |
| if (hash !== last_hash && re.test(hash)) { | |
| _this.last_hash = hash; | |
| callback({ | |
| data: decodeJson(encodeURIComponent(hash.replace(re, ""))) | |
| }); | |
| } | |
| }; | |
| })(this), 100); | |
| } | |
| } | |
| }; | |
| // Helpers | |
| /** | |
| * JSON.parse | |
| * @return {Object} | |
| */ | |
| var decodeJson = function (string){ | |
| var out = {}, | |
| array = string.split('&'); | |
| for(var i = 0; i < array.length; i++){ | |
| var match = array[i].split('='); | |
| out[match[0]] = match[1]; | |
| } | |
| return out; | |
| }; | |
| /** | |
| * JSON.stringify | |
| * @return {String} | |
| */ | |
| var encodeJson = function (obj){ | |
| var out = []; | |
| for( var i in obj ){ | |
| obj.hasOwnProperty(i) && out.push(i+'='+obj[i]); | |
| } | |
| return out.join('&'); | |
| }; | |
| /** | |
| * Crossbrowser remove element | |
| */ | |
| var removeElement = function(element){ | |
| element && element.parentNode && element.parentNode.removeChild(element); | |
| }; | |
| /** | |
| * indexOf for IE < 9 | |
| * @return {bool} | |
| */ | |
| if (!Array.prototype.indexOf){ | |
| Array.prototype.indexOf = function(elt /*, from*/){ | |
| var len = this.length >>> 0; | |
| var from = Number(arguments[1]) || 0; | |
| from = (from < 0) | |
| ? Math.ceil(from) | |
| : Math.floor(from); | |
| if (from < 0) | |
| from += len; | |
| for (; from < len; from++) | |
| { | |
| if (from in this && | |
| this[from] === elt) | |
| return from; | |
| } | |
| return -1; | |
| }; | |
| } | |
| if(typeof exc_config === 'object'){ | |
| window.EX = new EX(exc_config); | |
| }else{ | |
| window.EX = EX; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment