quad-tap
Version:
A pure JavaScript implementation of the Quad-Tap overlay interaction for videos with advanced video player API integration
1,183 lines (1,163 loc) • 182 kB
JavaScript
var t;
t = () => ( () => {
var t = {
d: (e, o) => {
for (var n in o)
t.o(o, n) && !t.o(e, n) && Object.defineProperty(e, n, {
enumerable: !0,
get: o[n]
})
}
,
o: (t, e) => Object.prototype.hasOwnProperty.call(t, e)
}
, e = {};
function o(t) {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}
, o = document.createElement(t);
if (e.className && (o.className = e.className),
e.id && (o.id = e.id),
e.text && (o.textContent = e.text),
e.html && (o.innerHTML = e.html),
e.attributes)
for (var n in e.attributes)
o.setAttribute(n, e.attributes[n]);
if (e.styles)
for (var i in e.styles)
o.style[i] = e.styles[i];
if (e.events)
for (var a in e.events)
o.addEventListener(a, e.events[a]);
return e.children && e.children.forEach((function(t) {
o.appendChild(t)
}
)),
o
}
function n(t, e, o) {
if (arguments.length > 3 && void 0 !== arguments[3] && arguments[3]) {
var n = t.parentElement;
if (n) {
var i = n.getBoundingClientRect();
e = i.width * e,
o = i.height * o
}
}
t.style.left = e + "px",
t.style.top = o + "px",
t.style.transform = "translate(-50%, -50%)"
}
function i(t) {
return i = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) {
return typeof t
}
: function(t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
}
,
i(t)
}
t.d(e, {
default: () => M
});
var a = "quadTap_";
function r(t, e) {
try {
var o = a + t;
return "object" === i(e) ? localStorage.setItem(o, JSON.stringify(e)) : localStorage.setItem(o, e),
!0
} catch (t) {
return console.error("[QuadTap] Error saving to localStorage:", t),
!1
}
}
function s(t) {
var e = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : null;
try {
var o = a + t
, n = localStorage.getItem(o);
if (null === n)
return e;
try {
return JSON.parse(n)
} catch (t) {
return n
}
} catch (t) {
return console.error("[QuadTap] Error retrieving from localStorage:", t),
e
}
}
function l(t) {
return l = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) {
return typeof t
}
: function(t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
}
,
l(t)
}
function d() {
d = function() {
return e
}
;
var t, e = {}, o = Object.prototype, n = o.hasOwnProperty, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", r = i.asyncIterator || "@@asyncIterator", s = i.toStringTag || "@@toStringTag";
function c(t, e, o, n) {
return Object.defineProperty(t, e, {
value: o,
enumerable: !n,
configurable: !n,
writable: !n
})
}
try {
c({}, "")
} catch (t) {
c = function(t, e, o) {
return t[e] = o
}
}
function u(e, o, n, i) {
var a = o && o.prototype instanceof g ? o : g
, r = Object.create(a.prototype);
return c(r, "_invoke", function(e, o, n) {
var i = 1;
return function(a, r) {
if (3 === i)
throw Error("Generator is already running");
if (4 === i) {
if ("throw" === a)
throw r;
return {
value: t,
done: !0
}
}
for (n.method = a,
n.arg = r; ; ) {
var s = n.delegate;
if (s) {
var l = j(s, n);
if (l) {
if (l === p)
continue;
return l
}
}
if ("next" === n.method)
n.sent = n._sent = n.arg;
else if ("throw" === n.method) {
if (1 === i)
throw i = 4,
n.arg;
n.dispatchException(n.arg)
} else
"return" === n.method && n.abrupt("return", n.arg);
i = 3;
var d = h(e, o, n);
if ("normal" === d.type) {
if (i = n.done ? 4 : 2,
d.arg === p)
continue;
return {
value: d.arg,
done: n.done
}
}
"throw" === d.type && (i = 4,
n.method = "throw",
n.arg = d.arg)
}
}
}(e, n, new T(i || [])), !0),
r
}
function h(t, e, o) {
try {
return {
type: "normal",
arg: t.call(e, o)
}
} catch (t) {
return {
type: "throw",
arg: t
}
}
}
e.wrap = u;
var p = {};
function g() {}
function m() {}
function f() {}
var b = {};
c(b, a, (function() {
return this
}
));
var v = Object.getPrototypeOf
, y = v && v(v(B([])));
y && y !== o && n.call(y, a) && (b = y);
var w = f.prototype = g.prototype = Object.create(b);
function x(t) {
["next", "throw", "return"].forEach((function(e) {
c(t, e, (function(t) {
return this._invoke(e, t)
}
))
}
))
}
function C(t, e, o) {
var n = document.createElement("button");
w(n, b);
// Detect if we're on mobile or small screen
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
var isSmallScreen = window.innerWidth < 768;
// Apply responsive styles for buttons on mobile/small screens
if (isMobile || isSmallScreen) {
n.style.width = "26px";
n.style.height = "26px";
n.style.margin = "0 2px";
n.style.fontSize = "13px";
}
// Fix alignment issues - using a single block of style definitions
n.style.display = "flex";
n.style.alignItems = "center";
n.style.justifyContent = "center";
n.style.lineHeight = "1";
n.style.padding = "0"; // Remove any default padding
n.style.verticalAlign = "middle";
n.textContent = t;
n.setAttribute("aria-label", e);
n.addEventListener("mouseenter", (function() {
w(n, v)
})),
n.addEventListener("mouseleave", (function() {
n.style.backgroundColor = ""
})),
n.addEventListener("click", function(e) {
e.preventDefault();
o(e);
}),
// Add touch events for mobile
n.addEventListener("touchstart", function(e) {
e.preventDefault(); // Prevent default touch behavior
w(n, v); // Apply hover style on touch
}),
n.addEventListener("touchend", function(e) {
e.preventDefault(); // Prevent default touch behavior
n.style.backgroundColor = ""; // Reset style
o(e); // Call the original handler
}),
n.addEventListener("touchcancel", function(e) {
n.style.backgroundColor = ""; // Reset style on touch cancel
});
return n;
}
function j(t) {
var n = o.method
, i = e.i[n];
if (i === t)
return o.delegate = null,
"throw" === n && e.i.return && (o.method = "return",
o.arg = t,
j(e, o),
"throw" === o.method) || "return" !== n && (o.method = "throw",
o.arg = new TypeError("The iterator does not provide a '" + n + "' method")),
p;
var a = h(i, e.i, o.arg);
if ("throw" === a.type)
return o.method = "throw",
o.arg = a.arg,
o.delegate = null,
p;
var r = a.arg;
return r ? r.done ? (o[e.r] = r.value,
o.next = e.n,
"return" !== o.method && (o.method = "next",
o.arg = t),
o.delegate = null,
p) : r : (o.method = "throw",
o.arg = new TypeError("iterator result is not an object"),
o.delegate = null,
p)
}
function k(t) {
this.tryEntries.push(t)
}
function S(e) {
var o = e[4] || {};
o.type = "normal",
o.arg = t,
e[4] = o
}
function T(t) {
this.tryEntries = [[-1]],
t.forEach(k, this),
this.reset(!0)
}
function B(e) {
if (null != e) {
var o = e[a];
if (o)
return o.call(e);
if ("function" == typeof e.next)
return e;
if (!isNaN(e.length)) {
var i = -1
, r = function o() {
for (; ++i < e.length; )
if (n.call(e, i))
return o.value = e[i],
o.done = !1,
o;
return o.value = t,
o.done = !0,
o
};
return r.next = r
}
}
throw new TypeError(l(e) + " is not iterable")
}
return m.prototype = f,
c(w, "constructor", f),
c(f, "constructor", m),
m.displayName = c(f, s, "GeneratorFunction"),
e.isGeneratorFunction = function(t) {
var e = "function" == typeof t && t.constructor;
return !!e && (e === m || "GeneratorFunction" === (e.displayName || e.name))
}
,
e.mark = function(t) {
return Object.setPrototypeOf ? Object.setPrototypeOf(t, f) : (t.__proto__ = f,
c(t, s, "GeneratorFunction")),
t.prototype = Object.create(w),
t
}
,
e.awrap = function(t) {
return {
__await: t
}
}
,
x(C.prototype),
c(C.prototype, r, (function() {
return this
}
)),
e.AsyncIterator = C,
e.async = function(t, o, n, i, a) {
void 0 === a && (a = Promise);
var r = new C(u(t, o, n, i),a);
return e.isGeneratorFunction(o) ? r : r.next().then((function(t) {
return t.done ? t.value : r.next()
}
))
}
,
x(w),
c(w, s, "Generator"),
c(w, a, (function() {
return this
}
)),
c(w, "toString", (function() {
return "[object Generator]"
}
)),
e.keys = function(t) {
var e = Object(t)
, o = [];
for (var n in e)
o.unshift(n);
return function t() {
for (; o.length; )
if ((n = o.pop())in e)
return t.value = n,
t.done = !1,
t;
return t.done = !0,
t
}
}
,
e.values = B,
T.prototype = {
constructor: T,
reset: function(e) {
if (this.prev = this.next = 0,
this.sent = this._sent = t,
this.done = !1,
this.delegate = null,
this.method = "next",
this.arg = t,
this.tryEntries.forEach(S),
!e)
for (var o in this)
"t" === o.charAt(0) && n.call(this, o) && !isNaN(+o.slice(1)) && (this[o] = t)
},
stop: function() {
this.done = !0;
var t = this.tryEntries[0][4];
if ("throw" === t.type)
throw t.arg;
return this.rval
},
dispatchException: function(e) {
if (this.done)
throw e;
var o = this;
function n(t) {
r.type = "throw",
r.arg = e,
o.next = t
}
for (var i = o.tryEntries.length - 1; i >= 0; --i) {
var a = this.tryEntries[i]
, r = a[4]
, s = this.prev
, l = a[1]
, d = a[2];
if (-1 === a[0])
return n("end"),
!1;
if (!l && !d)
throw Error("try statement without catch or finally");
if (null != a[0] && a[0] <= s) {
if (s < l)
return this.method = "next",
this.arg = t,
n(l),
!0;
if (s < d)
return n(d),
!1
}
}
},
abrupt: function(t, e) {
for (var o = this.tryEntries.length - 1; o >= 0; --o) {
var n = this.tryEntries[o];
if (n[0] > -1 && n[0] <= this.prev && this.prev < n[2]) {
var i = n;
break
}
}
i && ("break" === t || "continue" === t) && i[0] <= e && e <= i[2] && (i = null);
var a = i ? i[4] : {};
return a.type = t,
a.arg = e,
i ? (this.method = "next",
this.next = i[2],
p) : this.complete(a)
},
complete: function(t, e) {
if ("throw" === t.type)
throw t.arg;
return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg,
this.method = "return",
this.next = "end") : "normal" === t.type && e && (this.next = e),
p
},
finish: function(t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var o = this.tryEntries[e];
if (o[2] === t)
return this.complete(o[4], o[3]),
S(o),
p
}
},
catch: function(t) {
for (var e = this.tryEntries.length - 1; e >= 0; --e) {
var o = this.tryEntries[e];
if (o[0] === t) {
var n = o[4];
if ("throw" === n.type) {
var i = n.arg;
S(o)
}
return i
}
}
throw Error("illegal catch attempt")
},
delegateYield: function(e, o, n) {
return this.delegate = {
i: B(e),
r: o,
n
},
"next" === this.method && (this.arg = t),
p
}
},
e
}
function c(t, e, o, n, i, a, r) {
try {
var s = t[a](r)
, l = s.value
} catch (t) {
return void o(t)
}
s.done ? e(l) : Promise.resolve(l).then(n, i)
}
function u(t) {
return function() {
var e = this
, o = arguments;
return new Promise((function(n, i) {
var a = t.apply(e, o);
function r(t) {
c(a, n, i, r, s, "next", t)
}
function s(t) {
c(a, n, i, r, s, "throw", t)
}
r(void 0)
}
))
}
}
function h() {
return (h = u(d().mark((function t(e) {
var o, n, i;
return d().wrap((function(t) {
for (; ; )
switch (t.prev = t.next) {
case 0:
if (n = e.elements.video,
!(i = (null === (o = e.config.videoPlayerApi) || void 0 === o ? void 0 : o.enabled) && e.config.videoPlayerApi.adapter)) {
t.next = 7;
break
}
return t.next = 5,
i.play();
case 5:
t.next = 16;
break;
case 7:
if (!n) {
t.next = 16;
break
}
return t.prev = 8,
t.next = 11,
n.play();
case 11:
t.next = 16;
break;
case 13:
t.prev = 13,
t.t0 = t.catch(8),
console.error("Error resuming video playback:", t.t0);
case 16:
case "end":
return t.stop()
}
}
), t, null, [[8, 13]])
}
)))).apply(this, arguments)
}
function p() {
return (p = u(d().mark((function t(e) {
var o, n, i;
return d().wrap((function(t) {
for (; ; )
switch (t.prev = t.next) {
case 0:
if (n = e.elements.video,
!(i = (null === (o = e.config.videoPlayerApi) || void 0 === o ? void 0 : o.enabled) && e.config.videoPlayerApi.adapter)) {
t.next = 11;
break
}
// QuadTap MOD: Unconditionally pause if adapter exists
return t.next = 5,
i.pause();
case 5:
// e.state.wasPlayingBefore = t.sent; // QuadTap MOD: Removed wasPlayingBefore logic
// if (!e.state.wasPlayingBefore) {
// t.next = 9;
// break
// }
// return t.next = 9,
// i.pause();
// case 9:
t.next = 12; // QuadTap MOD: Skip to end after pause
break;
case 11:
// QuadTap MOD: Unconditionally pause if native video element exists
n && n.pause();
// e.state.wasPlayingBefore = !1; // QuadTap MOD: Removed wasPlayingBefore logic
case 12:
case "end":
return t.stop()
}
}
), t)
}
)))).apply(this, arguments)
}
var g = {
width: "60%", // Adjusted from 70%
maxWidth: "350px", // Adjusted from 420px
height: "auto",
padding: "6px 10px", // Slightly reduced padding
borderRadius: "24px",
backgroundColor: "rgba(0, 0, 0, 0.7)",
display: "flex",
justifyContent: "space-around", // Restored original space-around
alignItems: "center",
boxShadow: "0 2px 8px rgba(0, 0, 0, 0.3)",
transition: "opacity 0.3s ease, width 0.3s ease, padding 0.3s ease"
}
, m = {
position: "absolute",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)"
}
, f = {
position: "static",
top: "",
left: "",
transform: "",
margin: "20px auto"
}
, b = {
width: "30px", // Adjusted from 32px
height: "30px", // Adjusted from 32px
margin: "0 3px", // Adjusted from 4px
borderRadius: "50%",
border: "none",
backgroundColor: "rgba(255, 255, 255, 0.2)",
color: "white",
fontSize: "14px", // Adjusted from 15px
cursor: "pointer",
outline: "none",
display: "flex",
justifyContent: "center",
alignItems: "center",
transition: "background-color 0.2s ease"
}
, v = {
backgroundColor: "rgba(255, 255, 255, 0.2)"
}
, y = {
position: "absolute",
backgroundColor: "rgba(0, 0, 0, 0.8)",
color: "white",
padding: "5px 10px",
borderRadius: "4px",
fontSize: "14px",
zIndex: "2000",
pointerEvents: "none",
opacity: "0",
transition: "opacity 0.3s ease"
};
function w(t, e) {
Object.assign(t.style, e)
}
function x(t) {
var e = t.overlay
, o = t.onPlay
, n = t.onPause
, i = t.onRewind
, a = t.onForward
, r = t.onShare
, s = t.onCopyUrl
, l = t.rewindTime
, d = void 0 === l ? 30 : l
, c = t.forwardTime
, u = void 0 === c ? 30 : c
, h = t.debug
, p = void 0 !== h && h
, b = t.showAllButtons
, v = void 0 !== b && b
, y = t.isLightbox
, x = void 0 !== y && y
, j = document.createElement("div");
// Apply base styles
w(j, g);
w(j, x ? f : m);
// Detect if we're on mobile or small screen
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
var isSmallScreen = window.innerWidth < 768;
// Apply responsive styles for mobile/small screens
if (isMobile || isSmallScreen) {
// Narrower on mobile but not too narrow
j.style.width = "65%";
j.style.maxWidth = "280px";
j.style.padding = "5px 8px";
}
if (!x) {
var T = parseInt(getComputedStyle(e).zIndex) || 1e3;
j.style.zIndex = (T + 10).toString()
}
var B = C("⟲" + d, "Rewind " + d + " seconds", i)
, E = C("▶", "Play/Pause", (function(t) {
var e = "▶" === E.textContent;
E.textContent = e ? "❚❚" : "▶",
e ? o(t) : n(t)
}
))
, q = C("⟳" + u, "Forward " + u + " seconds", a)
, P = C("⤴", "Share", (function(t) {
if (t.stopPropagation(),
r)
r(t);
else {
var e = window.location.href;
navigator.share ? navigator.share({
title: "Check out this video moment",
url: e
}).catch((function(t) {
console.error("Error sharing:", t)
}
)) : (k(e),
S(P, "Link copied!"))
}
}
))
, O = C("⧉", "Copy URL", (function(t) {
t.stopPropagation(),
s ? s(t) : (k(window.location.href),
S(O, "Link copied!"))
}
));
if (j.appendChild(B),
j.appendChild(E),
j.appendChild(q),
(v || x) && (j.appendChild(P),
j.appendChild(O)),
// Add click event handler to stop propagation
j.addEventListener("click", (function(t) {
t.stopPropagation(),
p && console.log("[QuadTap] Control strip clicked, propagation stopped")
})),
// Add touch event handlers for mobile
j.addEventListener("touchstart", function(t) {
t.stopPropagation();
j.style.opacity = "1";
p && console.log("[QuadTap] Control strip touch started, propagation stopped");
}),
j.addEventListener("touchend", function(t) {
t.stopPropagation();
p && console.log("[QuadTap] Control strip touch ended, propagation stopped");
}),
j.addEventListener("touchmove", function(t) {
t.stopPropagation();
}),
e.appendChild(j),
!x) {
var z, L = function() {
j.style.opacity = "0.5"
};
j.addEventListener("mouseenter", (function() {
clearTimeout(z),
j.style.opacity = "1"
}
)),
j.addEventListener("mouseleave", (function() {
clearTimeout(z),
z = setTimeout(L, 2e3)
}
)),
j.style.opacity = "1",
z = setTimeout(L, 2e3)
}
return p && (console.log("[QuadTap] Control strip created with positioning:", {
isLightbox: x,
className: j.className,
zIndex: j.style.zIndex
}),
x || new ResizeObserver((function() {
var t = j.getBoundingClientRect()
, o = e.getBoundingClientRect()
, n = (t.top - o.top + t.height / 2) / o.height * 100
, i = (t.left - o.left + t.width / 2) / o.width * 100;
console.log("[QuadTap] Control strip position after resize:", {
topPercent: n.toFixed(2) + "%",
leftPercent: i.toFixed(2) + "%",
width: t.width,
height: t.height
})
}
)).observe(e)),
j
}
function C(t, e, o) {
var n = document.createElement("button");
w(n, b);
// Detect if we're on mobile or small screen
var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
var isSmallScreen = window.innerWidth < 768;
// Apply responsive styles for buttons on mobile/small screens
if (isMobile || isSmallScreen) {
n.style.width = "26px";
n.style.height = "26px";
n.style.margin = "0 2px";
n.style.fontSize = "13px";
}
// Fix alignment issues - using a single block of style definitions
n.style.display = "flex";
n.style.alignItems = "center";
n.style.justifyContent = "center";
n.style.lineHeight = "1";
n.style.padding = "0"; // Remove any default padding
n.style.verticalAlign = "middle";
n.textContent = t;
n.setAttribute("aria-label", e);
n.addEventListener("mouseenter", (function() {
w(n, v)
})),
n.addEventListener("mouseleave", (function() {
n.style.backgroundColor = ""
})),
n.addEventListener("click", function(e) {
e.preventDefault();
o(e);
}),
// Add touch events for mobile
n.addEventListener("touchstart", function(e) {
e.preventDefault(); // Prevent default touch behavior
w(n, v); // Apply hover style on touch
}),
n.addEventListener("touchend", function(e) {
e.preventDefault(); // Prevent default touch behavior
n.style.backgroundColor = ""; // Reset style
o(e); // Call the original handler
}),
n.addEventListener("touchcancel", function(e) {
n.style.backgroundColor = ""; // Reset style on touch cancel
});
return n;
}
function j(t, e) {
var o = t.querySelector("button:nth-child(2)");
o && (o.textContent = e ? "❚❚" : "▶")
}
function k(t) {
if (navigator.clipboard && navigator.clipboard.writeText)
navigator.clipboard.writeText(t).catch((function(t) {
console.error("Failed to copy text: ", t)
}
));
else {
var e = document.createElement("textarea");
e.value = t,
e.style.position = "fixed",
document.body.appendChild(e),
e.select();
try {
document.execCommand("copy")
} catch (t) {
console.error("Failed to copy text: ", t)
}
document.body.removeChild(e)
}
}
function S(t, e) {
var o = document.createElement("div");
w(o, y),
o.textContent = e;
var n = t.getBoundingClientRect();
o.style.top = "".concat(n.top - 30, "px"),
o.style.left = "".concat(n.left + n.width / 2, "px"),
o.style.transform = "translateX(-50%)",
document.body.appendChild(o),
setTimeout((function() {
o.style.opacity = "1"
}
), 10),
setTimeout((function() {
o.style.opacity = "0",
setTimeout((function() {
document.body.removeChild(o)
}
), 300)
}
), 1500)
}
function T(t) {
return T = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(t) {
return typeof t
}
: function(t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
}
,
T(t)
}
function B(t, e) {
for (var o = 0; o < e.length; o++) {
var n = e[o];
n.enumerable = n.enumerable || !1,
n.configurable = !0,
"value"in n && (n.writable = !0),
Object.defineProperty(t, E(n.key), n)
}
}
function E(t) {
var e = function(t) {
if ("object" != T(t) || !t)
return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var o = e.call(t, "string");
if ("object" != T(o))
return o;
throw new TypeError("@@toPrimitive must return a primitive value.")
}
return String(t)
}(t);
return "symbol" == T(e) ? e : e + ""
}
var q = {
containerId: "main-video-droppable",
videoSelector: "#main-video",
autoCancelTimeout: 5e3,
debug: !0,
emojis: {
quadrants: {
topLeft: "🕊️",
topRight: "🌟",
bottomLeft: "🌧️",
bottomRight: "💥"
},
directional: {
up: "🚀",
right: "👑",
down: "⬇️",
left: "🤫"
},
thoughts: {
topLeft: ["🌸", "🎈", "🌦️", "🛤️"],
topRight: ["🌈", "✨", "🌤️", "🎆"],
bottomLeft: ["🍂", "🌙", "☔", "🗿"],
bottomRight: ["⚖️", "🏆", "⛈️", "💣"]
}
},
videoControls: {
enabled: !0,
rewindTime: 30,
forwardTime: 30
},
callbacks: {
onOverlayActivate: null,
onThrowDownInitiate: null,
onThrowDownConfirm: null,
onThrowDownCancel: null,
onVideoControl: null
}
};
const P = function() {
return t = function t() {
var e, o, n = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
!function(t, e) {
if (!(t instanceof e))
throw new TypeError("Cannot call a class as a function")
}(this, t),
this.config = Object.assign({}, q, n),
n.emojis && (this.config.emojis = Object.assign({}, q.emojis, n.emojis),
n.emojis.quadrants && (this.config.emojis.quadrants = Object.assign({}, q.emojis.quadrants, n.emojis.quadrants)),
n.emojis.directional && (this.config.emojis.directional = Object.assign({}, q.emojis.directional, n.emojis.directional)),
n.emojis.thoughts && (this.config.emojis.thoughts = Object.assign({}, q.emojis.thoughts, n.emojis.thoughts))),
n.videoControls && (this.config.videoControls = Object.assign({}, q.videoControls, n.videoControls)),
n.profileBubble ? this.config.profileBubble = Object.assign({}, {
imageUrl: null,
fallbackEmoji: "👤",
size: "60px",
borderColor: "white",
borderWidth: "2px",
backgroundColor: "rgba(0, 0, 0, 0.7)"
}, n.profileBubble) : this.config.profileBubble = {
imageUrl: null,
fallbackEmoji: "👤",
size: "60px",
borderColor: "white",
borderWidth: "2px",
backgroundColor: "rgba(0, 0, 0, 0.7)"
},
n.colors ? (this.config.colors = {
overlay: {
background: "rgba(240, 240, 245, 0.5)",
quadrantGradients: {
topLeft: "rgba(0, 255, 255, 0.8)",
topRight: "rgba(255, 255, 0, 0.8)",
bottomLeft: "rgba(0, 255, 0, 0.8)",
bottomRight: "rgba(255, 0, 255, 0.8)"
}
},
lightbox: {
background: "rgba(20, 30, 40, 0.95)",
text: "white",
headerBackground: "rgba(30, 40, 60, 0.8)",
buttonPrimary: "#4CAF50",
buttonSecondary: "#f44336"
}
},
n.colors.overlay && (this.config.colors.overlay = Object.assign({}, this.config.colors.overlay, n.colors.overlay),
n.colors.overlay.quadrantGradients && (this.config.colors.overlay.quadrantGradients = Object.assign({}, this.config.colors.overlay.quadrantGradients, n.colors.overlay.quadrantGradients))),
n.colors.lightbox && (this.config.colors.lightbox = Object.assign({}, this.config.colors.lightbox, n.colors.lightbox))) : this.config.colors = {
overlay: {
background: "rgba(240, 240, 245, 0.5)",
quadrantGradients: {
topLeft: "rgba(0, 255, 255, 0.8)",
topRight: "rgba(255, 255, 0, 0.8)",
bottomLeft: "rgba(0, 255, 0, 0.8)",
bottomRight: "rgba(255, 0, 255, 0.8)"
}
},
lightbox: {
background: "rgba(20, 30, 40, 0.95)",
text: "white",
headerBackground: "rgba(30, 40, 60, 0.8)",
buttonPrimary: "#4CAF50",
buttonSecondary: "#f44336"
}
},
this.state = {
active: !1,
profileBubblePosition: {
x: 0,
y: 0
},
currentQuadrant: null,
autoCancelTimer: null,
containerDimensions: {
width: 0,
height: 0
},
videoPlaying: !1,
wasPlayingBefore: !1,
recording: !1,
mediaStream: null,
mediaRecorder: null,
recordingStartTime: 0,
recordingIndicator: null,
swipeDebounceTimer: null, // For debounce timing
swipeProcessing: !1 // Add this to track active swipe processing
},
this.elements = {
container: null,
video: null,
overlay: null,
profileBubble: null,
directionalEmojis: {},
quadrantEmojis: {},
videoControls: null,
tooltip: null,
lightBox: null,
lightBoxContent: null,
emojiGrid: null,
commentBox: null
},
this.throttledResize = (e = this.handleResize.bind(this),
function() {
o || (e.apply(void 0, arguments),
o = !0,
setTimeout((function() {
o = !1
}
), 100))
}
),
this.init()
}
,
e = [{
key: "log",
value: function(t, e) {
this.config.debug && console.log("[QuadTap] ".concat(t), e || "")
}
}, {
key: "init",
value: function() {
this.log("Initializing QuadTap");
var t = document.getElementById(this.config.containerId);
t ? (this.elements.container = t,
function() {
if (!document.getElementById("quad-tap-styles")) {
var t = document.createElement("style");
t.id = "quad-tap-styles",
t.textContent = "\n /* Overlay Container */\n .overlay-container {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.3s ease;\n z-index: 1000;\n background-color: rgba(240, 240, 245, 0.5);\n }\n \n .overlay-container.active {\n opacity: 1;\n pointer-events: auto;\n }\n \n /* Block pointer events on video when overlay is active */\n .overlay-container.active + video,\n .quad-tap-overlay.active + video {\n pointer-events: none;\n }\n \n /* Quadrants */\n .quadrant {\n position: absolute;\n width: 50%;\n height: 50%;\n opacity: 0.8;\n transition: opacity 0.3s ease;\n }\n \n .quadrant.top-left {\n top: 0;\n left: 0;\n background: linear-gradient(135deg, rgba(0, 255, 255, 0.8), rgba(0, 255, 255, 0));\n }\n \n .quadrant.top-right {\n top: 0;\n right: 0;\n background: linear-gradient(225deg, rgba(255, 255, 0, 0.8), rgba(255, 255, 0, 0));\n }\n \n .quadrant.bottom-left {\n bottom: 0;\n left: 0;\n background: linear-gradient(45deg, rgba(0, 255, 0, 0.8), rgba(0, 255, 0, 0));\n }\n \n .quadrant.bottom-right {\n bottom: 0;\n right: 0;\n background: linear-gradient(315deg, rgba(255, 0, 255, 0.8), rgba(255, 0, 255, 0));\n }\n \n /* Profile Bubble */\n .profile-bubble {\n position: absolute;\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background-color: rgba(128, 128, 128, 0.8);\n border: 2px solid white;\n box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);\n display: flex;\n justify-content: center;\n align-items: center;\n cursor: pointer;\n z-index: 1001;\n transform: translate(-50%, -50%);\n transition: transform 0.2s ease, box-shadow 0.2s ease;\n }\n \n .profile-bubble:hover {\n transform: translate(-50%, -50%) scale(1.1);\n box-shadow: 0 0 15px rgba(0, 0, 0, 0.7);\n }\n \n /* Light-Box Modal */\n .td-modal {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background-color: rgba(23, 32, 42, 0.7);\n z-index: 2000;\n justify-content: center;\n align-items: center;\n opacity: 0;\n transition: opacity 0.3s ease;\n }\n \n .td-modal.active {\n display: flex;\n opacity: 1;\n }\n \n .td-modal-content {\n background-color: white;\n padding: 20px;\n border-radius: 10px;\n width: 95%;\n max-width: 800px;\n max-height: 80vh;\n overflow-y: auto;\n position: relative;\n box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5);\n }\n \n .td-modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 20px;\n padding-bottom: 10px;\n border-bottom: 1px solid #eee;\n }\n \n .td-modal-header h4 {\n margin: 0;\n font-size: 1.5rem;\n color: #333;\n }\n \n .td-close-btn, .td-pause-play-btn {\n background: none;\n border: none;\n font-size: 1.5rem;\n cursor: pointer;\n color: #999;\n transition: color 0.2s ease;\n }\n \n .td-close-btn {\n margin-left: 10px;\n }\n \n .td-pause-play-btn {\n margin-left: auto;\n }\n \n .td-close-btn:hover, .td-pause-play-btn:hover {\n color: #333;\n }\n \n /* Emoji Grid */\n .emoji-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n grid-template-rows: 1fr 1fr;\n gap: 10px;\n width: 100%;\n }\n \n .emoji-quadrant {\n padding: 10px;\n border-radius: 8px;\n }\n \n .emoji-quadrant.top-left {\n background-color: rgba(0, 255, 255, 0.2);\n }\n \n .emoji-quadrant.top-right {\n background-color: rgba(255, 255, 0, 0.2);\n }\n \n .emoji-quadrant.bottom-left {\n background-color: rgba(0, 255, 0, 0.2);\n }\n \n .emoji-quadrant.bottom-right {\n background-color: rgba(255, 0, 255, 0.2);\n }\n \n .emoji-row {\n display: flex;\n justify-content: space-around;\n margin-bottom: 10px;\n background-color: transparent;\n }\n \n .emoji-cell {\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: transparent;\n }\n \n .thought-emoji {\n font-size: 2rem;\n cursor: pointer;\n padding: 5px;\n border-radius: 5px;\n transition: transform 0.2s ease, background-color 0.2s ease;\n }\n \n .thought-emoji:hover {\n transform: scale(1.2);\n background-color: rgba(255, 255, 255, 0.5);\n }\n \n .thought-emoji.selected {\n background-color: rgba(255, 255, 255, 0.8);\n box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);\n }\n \n /* Tooltip */\n .tooltip {\n position: absolute;\n background-color: rgba(0, 0, 0, 0.7);\n color: white;\n padding: 5px 10px;\n border-radius: 5px;\n font-size: 0.8rem;\n pointer-events: none;\n z-index: 1002;\n transition: opacity 0.3s ease;\n }\n \n /* Comment Box */\n .comment-box {\n margin-top: 20px;\n width: 100%;\n }\n \n .comment-box textarea {\n width: 100%;\n padding: 10px;\n border: 1px solid #ddd;\n border-radius: 5px;\n resize: vertical;\n min-height: 80px;\n font-family: inherit;\n }\n \n /* Media Buttons */\n .media-buttons {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n margin-top: 10px;\n margin-bottom: 10px;\n }\n \n .media-button {\n padding: 8px 12px;\n border: none;\n border-radius: 5px;\n cursor: pointer;\n font-weight: bold;\n transition: background-color 0.2s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n \n .upload-button {\n background-color: #3498db;\n color: white;\n }\n \n .upload-button:hover {\n background-color: #2980b9;\n }\n \n .capture-button {\n background-color: #e74c3c;\n color: white;\n }\n \n .capture-button:hover {\n background-color: #c0392b;\n }\n \n .uploaded-file-name {\n margin-top: 5px;\n padding: 5px;\n background-color: #f1f1f1;\n border-radius: 3px;\n font-size: 0.9rem;\n width: 100%;\n }\n \n .recording-message {\n margin-top: 5px;\n padding: 5px;\n background-color: #f8d7da;\n color: #721c24;\n border-radius: 3px;\n font-size: 0.9rem;\n width: 100%;\n }\n \n .recording-indicator {\n animation: pulse 1.5s infinite;\n }\n \n @keyframes pulse {\n 0% { opacity: 1; }\n 50% { opacity: 0.5; }\n 100% { opacity: 1; }\n }\n \n /* Action Buttons */\n .action-buttons {\n display: flex;\n justify-content: flex-end;\n margin-top: 20px;\n gap: 10px;\n }\n \n .action-button {\n padding: 8px 16px;\n border: none;\n border-radius: 5px;\n cursor: pointer;\n font-weight: bold;\n transition: background-color 0.2s ease;\n }\n \n .save-button {\n background-color: #4CAF50;\n color: white;\n }\n \n .save-button:hover {\n background-color: #45a049;\n }\n \n .cancel-button {\n background-color: #f44336;\n color: white;\n }\n \n .cancel-button:hover {\n background-color: #d32f2f;\n }\n ",
document.head.appendChild(t)
}
}(),
this.createOverlayElements(),
this.createLightBoxElements(),
this.bindEventHandlers(),
this.log("QuadTap initialized successfully")) : this.log("Container not found", this.config.containerId)
}
}, {
key: "createOverlayElements",
value: function() {
var t = this
, e = o("div", {
className: "quad-tap-overlay",
styles: {
display: "none",
backgroundColor: this.config.colors.overlay.background
}
})
, n = o("div", {
className: "overlay-close-btn",
html: "×",
styles: {
position: "absolute",
top: "10px",
right: "10px",
width: "30px",
height: "30px",
borderRadius: "50%",
backgroundColor: "rgba(0, 0, 0, 0.5)",
color: "white",
display: "flex",
justifyContent: "center",
alignItems: "center",
fontSize: "20px",
cursor: "pointer",
zIndex: "1002"
},
events: {
click: function(e) {
t.deactivateOverlay(),
e.stopPropagation()
}
}
})
, i = o("div", {
className: "quadrant top-left",
styles: {
background: "radial-gradient(circle at 0% 0%, ".concat(this.config.colors.overlay.quadrantGradients.topLeft, ", transparent 70%)")
}
})
, a = o("div", {
className: "quadrant top-right",
styles: {
background: "radial-gradient(circle at 100% 0%, ".concat(this.config.colors.overlay.quadrantGradients.topRight, ", transparent 70%)")
}
})
, r = o("div", {
className: "quadrant bottom-left",
styles: {
background: "radial-gradient(circle at 0% 100%, ".concat(this.config.colors.overlay.quadrantGradients.bottomLeft, ", transparent 70%)")
}
})
, s = o("div", {
className: "quadrant bottom-right",
styles: {
background: "radial-gradient(circle at 100% 100%, ".concat(this.config.colors.overlay.quadrantGradients.bottomRight, ", transparent 70%)")
}
})
, l = {
display: "none",
width: this.c