Skip to content

Instantly share code, notes, and snippets.

@masone
Last active January 27, 2017 11:47
Show Gist options
  • Save masone/a900827362712fafcaa2e3d4b9ce8f32 to your computer and use it in GitHub Desktop.
Save masone/a900827362712fafcaa2e3d4b9ce8f32 to your computer and use it in GitHub Desktop.
skyscanner
!function (e) {
function t() {
var t = e.skyscanner = e.skyscanner || {}, r = t.widgets = t.widgets || {}, a = r.renderCache = r.renderCache || {}, s = r.requests = r.requests || {};
return {widgets: r, renderCache: a, requests: s}
}
function r(e, t, r) {
t = t || "", r = r || {}, r.v = "6678ba";
var a = Object.keys(r).filter(function (e) {
return e && null !== r[e]
}).map(function (e) {
return encodeURIComponent(e) + "=" + encodeURIComponent(r[e])
}).join("&");
return e + t + "?" + a
}
function a(e, t) {
return r("https://widgets.skyscanner.net/widget-server", e, t)
}
function s(e, t) {
return r("https://www.skyscanner.net/g/widget-server", e, t)
}
function n(t, r) {
this.scope = r || o, this.xhr = e && e.XMLHttpRequest, this.element = t, this.locale = this.element.dataset.locale, this.widgetType = this.element.dataset.skyscannerWidget, this.params = {}, this.xhrParams = [], this.errors = [], this.serverUrl = "https://widgets.skyscanner.net/widget-server"
}
function i(t) {
if (e.document && e.document.querySelectorAll) {
var r = e.document.querySelectorAll(t);
return Array.prototype.slice.call(r)
}
}
var o = t(), c = ["locale", "skyscannerWidget", "skyscannerWidgetLoading", "params", "scriptParams", "locationParam", "locationName", "locationCoords", "locationPhrase", "locationIataCode"], l = /^\{(.+)\}$/, d = /^([^(]+)\(([^)]+)\)$/, h = n.prototype;
h.removeXhr = function (e) {
delete this.scope.requests[e]
}, h.getXhr = function (t, r, a) {
if (!this.scope.requests[t]) {
var s = new this.xhr;
s.addEventListener("loadend", this.removeXhr.bind(this, t)), s.open("GET", t, !0), r || s.setRequestHeader("Widget-Referrer", e.location && e.location.href), a && (s.withCredentials = !0), s.send(null), this.scope.requests[t] = s
}
return this.scope.requests[t]
}, h.addError = function (e, t) {
this.errors.push({message: e, error: t})
}, h.lookupLocation = function (e) {
for (var t in e)if (!e[t])return;
return this.getXhr(a("/v1.0/" + this.element.dataset.locale + "/location", e))
}, h.unregisterXhrParam = function (e) {
this.xhrParams = this.xhrParams.filter(function (t) {
return t.request !== e
})
}, h.handleXhrParamLoad = function (e, t) {
this.unregisterXhrParam(t), 4 !== t.readyState || 200 !== t.status ? this.setParam(e, null) : this.setParam(e, t.responseText), this.beginRender()
}, h.registerXhrParam = function (e, t) {
this.xhrParams.push({key: e, request: t}), t.addEventListener("load", this.handleXhrParamLoad.bind(this, e, t))
}, h.setSimpleParam = function (e, t) {
return void 0 === t ? void this.addError('Undefined parameter value for key "' + e + '"') : void(this.params[e] = t)
}, h.setComplexParams = function (e, t) {
var r = this, a = null;
if ("string" == typeof t)try {
a = JSON.parse(t)
} catch (e) {
this.addError("Error parsing JSON data: " + t)
} else a = t;
e.forEach(function (e) {
r.setSimpleParam(e.paramKey, a && a[e.objectKey] || null)
})
}, h.setParam = function (e, t) {
if (t instanceof this.xhr) this.registerXhrParam(e, t); else {
var r = e.match(l);
if (r) {
var a = r[1].split(",").map(function (e) {
return e.trim()
}).map(function (e) {
var t = e.match(d);
return t ? {paramKey: t[1], objectKey: t[2]} : {paramKey: e, objectKey: e}
});
this.setComplexParams(a, t)
} else this.setSimpleParam(e, t)
}
}, h.parseParamString = function (e) {
var t = {};
return e.split(";").forEach(function (e) {
var r = e.split(":");
e && r.length > 1 && (t[r[0]] = r[1])
}), t
}, h.parseFixedParams = function () {
var e = this, t = this.parseParamString(this.element.dataset.params);
Object.keys(t).forEach(function (r) {
e.setParam(r, t[r])
})
}, h.parseScriptedParams = function () {
var e = this, t = this.element, r = t.dataset.scriptParams;
if (r)try {
var a = JSON.parse(r);
Object.keys(a).forEach(function (t) {
var r = a[t];
if (t && r)try {
Array.isArray(r) && (r = r.join("\n"));
var s = function () {
return eval("(" + r + ")")
}.apply(e);
e.setParam(t, s)
} catch (r) {
e.addError('Error parsing scripted parameter "' + t + '"', r)
}
})
} catch (e) {
this.addError("Error parsing data-script-parameters: " + r, e)
}
}, h.parseLocationParams = function () {
var e = this, t = {
name: this.element.dataset.locationName || this.element.dataset.locationParam,
latlon: this.element.dataset.locationCoords,
phrase: this.element.dataset.locationPhrase,
iataCode: this.element.dataset.locationIataCode
}, r = {};
if (Object.keys(t).forEach(function (a) {
if (t[a])try {
var s = function () {
return eval("(" + t[a] + ")")
}.apply(e);
if ("undefined" == typeof s || "undefined" === s)throw"Undefined value";
r[a] = s
} catch (e) {
console.warn("Failed to evaluate location " + a + " script: " + e)
}
}), Object.keys(r).length > 0) {
var a = "{location(name),locationId(id)}", s = this.lookupLocation(r);
s && this.setParam(a, s)
}
}, h.parseAffiliateParams = function () {
var e = this.element.dataset.affiliate;
if (e) {
var t = JSON.stringify(this.parseParamString(e));
this.setParam("tracking", t)
}
}, h.beginRender = function () {
if (!(this.xhrParams.length > 0)) {
if (this.errors.length > 0)return console.log("Error(s) occured while loading widget", this), void this.errors.forEach(function (e) {
console.log(e.message), e.error && console.log(e.error)
});
var e = a("/v1.0/" + this.element.dataset.locale + "/widgets/" + this.element.dataset.skyscannerWidget, this.params);
if ("undefined" != typeof this.scope.renderCache[e]) this.render(this.scope.renderCache[e]); else {
var t = this.getXhr(e);
t.addEventListener("load", this.handleRenderLoad.bind(this, e, t))
}
}
}, h.handleRenderLoad = function (e, t) {
if (4 === t.readyState && 200 === t.status) {
var r = t.responseText;
this.scope.renderCache[e] = r, this.render(r)
}
}, h.render = function (e) {
var t = this;
try {
(function (__widget) {
eval(e)
}).call(this, this), this.replaceScriptNodes(), t.element.dataset.skyscannerWidgetLoaded = !0, this.personalise(), c.forEach(function (e) {
delete t.element.dataset[e]
})
} catch (e) {
t.element.dataset.skyscannerWidgetError = !0, console.error("Error rendering widget:", e)
}
}, h.personalise = function () {
var e = this, t = {};
Object.keys(e.params).forEach(function (r) {
t[r] = e.params[r]
}), t.locale = e.locale, t.widgetType = e.widgetType;
var r = s("/personalise", t), a = this.getXhr(r, !0, !0);
a.addEventListener("load", this.handlePersonalisationData.bind(this, a))
}, h.handlePersonalisationData = function (e) {
if (4 === e.readyState && 200 === e.status) {
var t = JSON.parse(e.responseText);
t.personalise && (void 0 !== t.message && (this.element.querySelector(".skyscanner-widget-text").innerHTML = t.message), void 0 !== t.referralUrl && (this.element.querySelector("a").href = t.referralUrl))
}
}, h.replaceScriptNodes = function () {
var t = this.element.querySelectorAll("script");
Array.prototype.forEach.call(t, function (t) {
if ("SCRIPT" === t.tagName) {
var r = e.document.createElement("script");
r.text = t.innerHTML, Array.prototype.forEach.call(t.attributes, function (e) {
"replace" !== e.name && r.setAttribute(e.name, e.value)
}), t.parentNode.replaceChild(r, t)
}
})
}, o.widgets.load = function (e) {
console.log('widgets.load')
e = e || i;
var t = e("[data-skyscanner-widget]");
console.log('widgets', t)
t && t.forEach(function (e) {
if (!(e.dataset.skyscannerWidgetLoading || e.dataset.skyscannerWidgetLoaded || e.dataset.skyscannerWidgetError)) {
e.dataset.skyscannerWidgetLoading = !0;
var t = new n(e);
t.parseFixedParams(), t.parseScriptedParams(), t.parseLocationParams(), t.parseAffiliateParams(), t.beginRender()
}
})
}, o.widgets.load(), "undefined" != typeof module && module.exports && (module.exports = {
getWidgetUrl: a,
WidgetElement: n,
globals: o
})
}("undefined" == typeof window ? global : window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment