2024-10-15 14:51:26 +08:00
|
|
|
import { t } from "../services/i18n.js";
|
2020-01-14 21:52:18 +01:00
|
|
|
import BasicWidget from "./basic_widget.js";
|
2022-08-05 16:44:26 +02:00
|
|
|
import contextMenu from "../menus/context_menu.js";
|
2020-01-19 21:24:14 +01:00
|
|
|
import utils from "../services/utils.js";
|
2020-01-20 22:35:52 +01:00
|
|
|
import keyboardActionService from "../services/keyboard_actions.js";
|
2022-12-01 13:07:23 +01:00
|
|
|
import appContext from "../components/app_context.js";
|
2021-04-16 23:01:56 +02:00
|
|
|
import froca from "../services/froca.js";
|
2021-08-25 22:49:24 +02:00
|
|
|
import attributeService from "../services/attributes.js";
|
2020-01-12 19:05:09 +01:00
|
|
|
|
2021-03-21 23:35:13 +01:00
|
|
|
/*!
|
|
|
|
|
* Draggabilly v2.3.0
|
|
|
|
|
* Make that shiz draggable
|
|
|
|
|
* https://draggabilly.desandro.com
|
|
|
|
|
* MIT license
|
|
|
|
|
*/
|
2025-01-09 18:07:02 +02:00
|
|
|
(function (e, i) {
|
|
|
|
|
e.jQueryBridget = i(e, e.jQuery);
|
|
|
|
|
})(window, function t(e, r) {
|
|
|
|
|
"use strict";
|
|
|
|
|
var s = Array.prototype.slice;
|
|
|
|
|
var i = e.console;
|
|
|
|
|
var f =
|
|
|
|
|
typeof i == "undefined"
|
|
|
|
|
? function () {}
|
|
|
|
|
: function (t) {
|
|
|
|
|
i.error(t);
|
|
|
|
|
};
|
|
|
|
|
function n(h, o, d) {
|
|
|
|
|
d = d || r || e.jQuery;
|
|
|
|
|
if (!d) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!o.prototype.option) {
|
|
|
|
|
o.prototype.option = function (t) {
|
|
|
|
|
if (!d.isPlainObject(t)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.options = d.extend(true, this.options, t);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
d.fn[h] = function (t) {
|
|
|
|
|
if (typeof t == "string") {
|
|
|
|
|
var e = s.call(arguments, 1);
|
|
|
|
|
return i(this, t, e);
|
|
|
|
|
}
|
|
|
|
|
n(this, t);
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
function i(t, r, s) {
|
|
|
|
|
var a;
|
|
|
|
|
var u = `$().${h}("${r}")`;
|
|
|
|
|
t.each(function (t, e) {
|
|
|
|
|
var i = d.data(e, h);
|
|
|
|
|
if (!i) {
|
|
|
|
|
f(`${h} not initialized. Cannot call methods, i.e. ${u}`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var n = i[r];
|
|
|
|
|
if (!n || r.charAt(0) == "_") {
|
|
|
|
|
f(`${u} is not a valid method`);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var o = n.apply(i, s);
|
|
|
|
|
a = a === undefined ? o : a;
|
|
|
|
|
});
|
|
|
|
|
return a !== undefined ? a : t;
|
|
|
|
|
}
|
|
|
|
|
function n(t, n) {
|
|
|
|
|
t.each(function (t, e) {
|
|
|
|
|
var i = d.data(e, h);
|
|
|
|
|
if (i) {
|
|
|
|
|
i.option(n);
|
|
|
|
|
i._init();
|
|
|
|
|
} else {
|
|
|
|
|
i = new o(e, n);
|
|
|
|
|
d.data(e, h, i);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
a(d);
|
|
|
|
|
}
|
|
|
|
|
function a(t) {
|
|
|
|
|
if (!t || (t && t.bridget)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
t.bridget = n;
|
|
|
|
|
}
|
|
|
|
|
a(r || e.jQuery);
|
|
|
|
|
return n;
|
|
|
|
|
});
|
|
|
|
|
(function (t, e) {
|
|
|
|
|
"use strict";
|
|
|
|
|
t.getSize = e();
|
|
|
|
|
})(window, function t() {
|
|
|
|
|
"use strict";
|
|
|
|
|
function m(t) {
|
|
|
|
|
var e = parseFloat(t);
|
|
|
|
|
var i = t.indexOf("%") == -1 && !isNaN(e);
|
|
|
|
|
return i && e;
|
|
|
|
|
}
|
|
|
|
|
function e() {}
|
|
|
|
|
var i =
|
|
|
|
|
typeof console == "undefined"
|
|
|
|
|
? e
|
|
|
|
|
: function (t) {
|
|
|
|
|
console.error(t);
|
|
|
|
|
};
|
|
|
|
|
var y = [
|
|
|
|
|
"paddingLeft",
|
|
|
|
|
"paddingRight",
|
|
|
|
|
"paddingTop",
|
|
|
|
|
"paddingBottom",
|
|
|
|
|
"marginLeft",
|
|
|
|
|
"marginRight",
|
|
|
|
|
"marginTop",
|
|
|
|
|
"marginBottom",
|
|
|
|
|
"borderLeftWidth",
|
|
|
|
|
"borderRightWidth",
|
|
|
|
|
"borderTopWidth",
|
|
|
|
|
"borderBottomWidth"
|
|
|
|
|
];
|
|
|
|
|
var b = y.length;
|
|
|
|
|
function E() {
|
|
|
|
|
var t = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 };
|
|
|
|
|
for (var e = 0; e < b; e++) {
|
|
|
|
|
var i = y[e];
|
|
|
|
|
t[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
function _(t) {
|
|
|
|
|
var e = getComputedStyle(t);
|
|
|
|
|
if (!e) {
|
|
|
|
|
i(`Style returned ${e}. Are you running this code in a hidden iframe on Firefox? See http://bit.ly/getsizebug1`);
|
|
|
|
|
}
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
var n = false;
|
|
|
|
|
var x;
|
|
|
|
|
function P() {
|
|
|
|
|
if (n) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
n = true;
|
|
|
|
|
var t = document.createElement("div");
|
|
|
|
|
t.style.width = "200px";
|
|
|
|
|
t.style.padding = "1px 2px 3px 4px";
|
|
|
|
|
t.style.borderStyle = "solid";
|
|
|
|
|
t.style.borderWidth = "1px 2px 3px 4px";
|
|
|
|
|
t.style.boxSizing = "border-box";
|
|
|
|
|
var e = document.body || document.documentElement;
|
|
|
|
|
e.appendChild(t);
|
|
|
|
|
var i = _(t);
|
|
|
|
|
o.isBoxSizeOuter = x = m(i.width) == 200;
|
|
|
|
|
e.removeChild(t);
|
|
|
|
|
}
|
|
|
|
|
function o(t) {
|
|
|
|
|
P();
|
|
|
|
|
if (typeof t == "string") {
|
|
|
|
|
t = document.querySelector(t);
|
|
|
|
|
}
|
|
|
|
|
if (!t || typeof t != "object" || !t.nodeType) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var e = _(t);
|
|
|
|
|
if (e.display == "none") {
|
|
|
|
|
return E();
|
|
|
|
|
}
|
|
|
|
|
var i = {};
|
|
|
|
|
i.width = t.offsetWidth;
|
|
|
|
|
i.height = t.offsetHeight;
|
|
|
|
|
var n = (i.isBorderBox = e.boxSizing == "border-box");
|
|
|
|
|
for (var o = 0; o < b; o++) {
|
|
|
|
|
var r = y[o];
|
|
|
|
|
var s = e[r];
|
|
|
|
|
var a = parseFloat(s);
|
|
|
|
|
i[r] = !isNaN(a) ? a : 0;
|
|
|
|
|
}
|
|
|
|
|
var u = i.paddingLeft + i.paddingRight;
|
|
|
|
|
var h = i.paddingTop + i.paddingBottom;
|
|
|
|
|
var d = i.marginLeft + i.marginRight;
|
|
|
|
|
var f = i.marginTop + i.marginBottom;
|
|
|
|
|
var p = i.borderLeftWidth + i.borderRightWidth;
|
|
|
|
|
var c = i.borderTopWidth + i.borderBottomWidth;
|
|
|
|
|
var v = n && x;
|
|
|
|
|
var l = m(e.width);
|
|
|
|
|
if (l !== false) {
|
|
|
|
|
i.width = l + (v ? 0 : u + p);
|
|
|
|
|
}
|
|
|
|
|
var g = m(e.height);
|
|
|
|
|
if (g !== false) {
|
|
|
|
|
i.height = g + (v ? 0 : h + c);
|
|
|
|
|
}
|
|
|
|
|
i.innerWidth = i.width - (u + p);
|
|
|
|
|
i.innerHeight = i.height - (h + c);
|
|
|
|
|
i.outerWidth = i.width + d;
|
|
|
|
|
i.outerHeight = i.height + f;
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
});
|
|
|
|
|
(function (t, e) {
|
|
|
|
|
t.EvEmitter = e();
|
|
|
|
|
})(typeof window != "undefined" ? window : this, function () {
|
|
|
|
|
function t() {}
|
|
|
|
|
var e = t.prototype;
|
|
|
|
|
e.on = function (t, e) {
|
|
|
|
|
if (!t || !e) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var i = (this._events = this._events || {});
|
|
|
|
|
var n = (i[t] = i[t] || []);
|
|
|
|
|
if (n.indexOf(e) == -1) {
|
|
|
|
|
n.push(e);
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
e.once = function (t, e) {
|
|
|
|
|
if (!t || !e) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.on(t, e);
|
|
|
|
|
var i = (this._onceEvents = this._onceEvents || {});
|
|
|
|
|
var n = (i[t] = i[t] || {});
|
|
|
|
|
n[e] = true;
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
e.off = function (t, e) {
|
|
|
|
|
var i = this._events && this._events[t];
|
|
|
|
|
if (!i || !i.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var n = i.indexOf(e);
|
|
|
|
|
if (n != -1) {
|
|
|
|
|
i.splice(n, 1);
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
e.emitEvent = function (t, e) {
|
|
|
|
|
var i = this._events && this._events[t];
|
|
|
|
|
if (!i || !i.length) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
i = i.slice(0);
|
|
|
|
|
e = e || [];
|
|
|
|
|
var n = this._onceEvents && this._onceEvents[t];
|
|
|
|
|
for (var o = 0; o < i.length; o++) {
|
|
|
|
|
var r = i[o];
|
|
|
|
|
var s = n && n[r];
|
|
|
|
|
if (s) {
|
|
|
|
|
this.off(t, r);
|
|
|
|
|
delete n[r];
|
|
|
|
|
}
|
|
|
|
|
r.apply(this, e);
|
|
|
|
|
}
|
|
|
|
|
return this;
|
|
|
|
|
};
|
|
|
|
|
e.allOff = function () {
|
|
|
|
|
delete this._events;
|
|
|
|
|
delete this._onceEvents;
|
|
|
|
|
};
|
|
|
|
|
return t;
|
|
|
|
|
});
|
|
|
|
|
(function (e, i) {
|
|
|
|
|
e.Unipointer = i(e, e.EvEmitter);
|
|
|
|
|
})(window, function t(o, e) {
|
|
|
|
|
function i() {}
|
|
|
|
|
function n() {}
|
|
|
|
|
var r = (n.prototype = Object.create(e.prototype));
|
|
|
|
|
r.bindStartEvent = function (t) {
|
|
|
|
|
this._bindStartEvent(t, true);
|
|
|
|
|
};
|
|
|
|
|
r.unbindStartEvent = function (t) {
|
|
|
|
|
this._bindStartEvent(t, false);
|
|
|
|
|
};
|
|
|
|
|
r._bindStartEvent = function (t, e) {
|
|
|
|
|
e = e === undefined ? true : e;
|
|
|
|
|
var i = e ? "addEventListener" : "removeEventListener";
|
|
|
|
|
var n = "mousedown";
|
|
|
|
|
if (o.PointerEvent) {
|
|
|
|
|
n = "pointerdown";
|
|
|
|
|
} else if ("ontouchstart" in o) {
|
|
|
|
|
n = "touchstart";
|
|
|
|
|
}
|
|
|
|
|
t[i](n, this);
|
|
|
|
|
};
|
|
|
|
|
r.handleEvent = function (t) {
|
|
|
|
|
var e = `on${t.type}`;
|
|
|
|
|
if (this[e]) {
|
|
|
|
|
this[e](t);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r.getTouch = function (t) {
|
|
|
|
|
for (var e = 0; e < t.length; e++) {
|
|
|
|
|
var i = t[e];
|
|
|
|
|
if (i.identifier == this.pointerIdentifier) {
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r.onmousedown = function (t) {
|
|
|
|
|
var e = t.button;
|
|
|
|
|
if (e && e !== 0 && e !== 1) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this._pointerDown(t, t);
|
|
|
|
|
};
|
|
|
|
|
r.ontouchstart = function (t) {
|
|
|
|
|
this._pointerDown(t, t.changedTouches[0]);
|
|
|
|
|
};
|
|
|
|
|
r.onpointerdown = function (t) {
|
|
|
|
|
this._pointerDown(t, t);
|
|
|
|
|
};
|
|
|
|
|
r._pointerDown = function (t, e) {
|
|
|
|
|
if (t.button || this.isPointerDown) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.isPointerDown = true;
|
|
|
|
|
this.pointerIdentifier = e.pointerId !== undefined ? e.pointerId : e.identifier;
|
|
|
|
|
this.pointerDown(t, e);
|
|
|
|
|
};
|
|
|
|
|
r.pointerDown = function (t, e) {
|
|
|
|
|
this._bindPostStartEvents(t);
|
|
|
|
|
this.emitEvent("pointerDown", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
var s = { mousedown: ["mousemove", "mouseup"], touchstart: ["touchmove", "touchend", "touchcancel"], pointerdown: ["pointermove", "pointerup", "pointercancel"] };
|
|
|
|
|
r._bindPostStartEvents = function (t) {
|
|
|
|
|
if (!t) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var e = s[t.type];
|
|
|
|
|
e.forEach(function (t) {
|
|
|
|
|
o.addEventListener(t, this);
|
|
|
|
|
}, this);
|
|
|
|
|
this._boundPointerEvents = e;
|
|
|
|
|
};
|
|
|
|
|
r._unbindPostStartEvents = function () {
|
|
|
|
|
if (!this._boundPointerEvents) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this._boundPointerEvents.forEach(function (t) {
|
|
|
|
|
o.removeEventListener(t, this);
|
|
|
|
|
}, this);
|
|
|
|
|
delete this._boundPointerEvents;
|
|
|
|
|
};
|
|
|
|
|
r.onmousemove = function (t) {
|
|
|
|
|
this._pointerMove(t, t);
|
|
|
|
|
};
|
|
|
|
|
r.onpointermove = function (t) {
|
|
|
|
|
if (t.pointerId == this.pointerIdentifier) {
|
|
|
|
|
this._pointerMove(t, t);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r.ontouchmove = function (t) {
|
|
|
|
|
var e = this.getTouch(t.changedTouches);
|
|
|
|
|
if (e) {
|
|
|
|
|
this._pointerMove(t, e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r._pointerMove = function (t, e) {
|
|
|
|
|
this.pointerMove(t, e);
|
|
|
|
|
};
|
|
|
|
|
r.pointerMove = function (t, e) {
|
|
|
|
|
this.emitEvent("pointerMove", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
r.onmouseup = function (t) {
|
|
|
|
|
this._pointerUp(t, t);
|
|
|
|
|
};
|
|
|
|
|
r.onpointerup = function (t) {
|
|
|
|
|
if (t.pointerId == this.pointerIdentifier) {
|
|
|
|
|
this._pointerUp(t, t);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r.ontouchend = function (t) {
|
|
|
|
|
var e = this.getTouch(t.changedTouches);
|
|
|
|
|
if (e) {
|
|
|
|
|
this._pointerUp(t, e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r._pointerUp = function (t, e) {
|
|
|
|
|
this._pointerDone();
|
|
|
|
|
this.pointerUp(t, e);
|
|
|
|
|
};
|
|
|
|
|
r.pointerUp = function (t, e) {
|
|
|
|
|
this.emitEvent("pointerUp", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
r._pointerDone = function () {
|
|
|
|
|
this._pointerReset();
|
|
|
|
|
this._unbindPostStartEvents();
|
|
|
|
|
this.pointerDone();
|
|
|
|
|
};
|
|
|
|
|
r._pointerReset = function () {
|
|
|
|
|
this.isPointerDown = false;
|
|
|
|
|
delete this.pointerIdentifier;
|
|
|
|
|
};
|
|
|
|
|
r.pointerDone = i;
|
|
|
|
|
r.onpointercancel = function (t) {
|
|
|
|
|
if (t.pointerId == this.pointerIdentifier) {
|
|
|
|
|
this._pointerCancel(t, t);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r.ontouchcancel = function (t) {
|
|
|
|
|
var e = this.getTouch(t.changedTouches);
|
|
|
|
|
if (e) {
|
|
|
|
|
this._pointerCancel(t, e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
r._pointerCancel = function (t, e) {
|
|
|
|
|
this._pointerDone();
|
|
|
|
|
this.pointerCancel(t, e);
|
|
|
|
|
};
|
|
|
|
|
r.pointerCancel = function (t, e) {
|
|
|
|
|
this.emitEvent("pointerCancel", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
n.getPointerPoint = function (t) {
|
|
|
|
|
return { x: t.pageX, y: t.pageY };
|
|
|
|
|
};
|
|
|
|
|
return n;
|
|
|
|
|
});
|
|
|
|
|
(function (e, i) {
|
|
|
|
|
e.Unidragger = i(e, e.Unipointer);
|
|
|
|
|
})(window, function t(r, e) {
|
|
|
|
|
function i() {}
|
|
|
|
|
var n = (i.prototype = Object.create(e.prototype));
|
|
|
|
|
n.bindHandles = function () {
|
|
|
|
|
this._bindHandles(true);
|
|
|
|
|
};
|
|
|
|
|
n.unbindHandles = function () {
|
|
|
|
|
this._bindHandles(false);
|
|
|
|
|
};
|
|
|
|
|
n._bindHandles = function (t) {
|
|
|
|
|
t = t === undefined ? true : t;
|
|
|
|
|
var e = t ? "addEventListener" : "removeEventListener";
|
|
|
|
|
var i = t ? this._touchActionValue : "";
|
|
|
|
|
for (var n = 0; n < this.handles.length; n++) {
|
|
|
|
|
var o = this.handles[n];
|
|
|
|
|
this._bindStartEvent(o, t);
|
|
|
|
|
o[e]("click", this);
|
|
|
|
|
if (r.PointerEvent) {
|
|
|
|
|
o.style.touchAction = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
n._touchActionValue = "none";
|
|
|
|
|
n.pointerDown = function (t, e) {
|
|
|
|
|
var i = this.okayPointerDown(t);
|
|
|
|
|
if (!i) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.pointerDownPointer = e;
|
|
|
|
|
t.preventDefault();
|
|
|
|
|
this.pointerDownBlur();
|
|
|
|
|
this._bindPostStartEvents(t);
|
|
|
|
|
this.emitEvent("pointerDown", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
var o = { TEXTAREA: true, INPUT: true, SELECT: true, OPTION: true };
|
|
|
|
|
var s = { radio: true, checkbox: true, button: true, submit: true, image: true, file: true };
|
|
|
|
|
n.okayPointerDown = function (t) {
|
|
|
|
|
var e = o[t.target.nodeName];
|
|
|
|
|
var i = s[t.target.type];
|
|
|
|
|
var n = !e || i;
|
|
|
|
|
if (!n) {
|
|
|
|
|
this._pointerReset();
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
};
|
|
|
|
|
n.pointerDownBlur = function () {
|
|
|
|
|
var t = document.activeElement;
|
|
|
|
|
var e = t && t.blur && t != document.body;
|
|
|
|
|
if (e) {
|
|
|
|
|
t.blur();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
n.pointerMove = function (t, e) {
|
|
|
|
|
var i = this._dragPointerMove(t, e);
|
|
|
|
|
this.emitEvent("pointerMove", [t, e, i]);
|
|
|
|
|
this._dragMove(t, e, i);
|
|
|
|
|
};
|
|
|
|
|
n._dragPointerMove = function (t, e) {
|
|
|
|
|
var i = { x: e.pageX - this.pointerDownPointer.pageX, y: e.pageY - this.pointerDownPointer.pageY };
|
|
|
|
|
if (!this.isDragging && this.hasDragStarted(i)) {
|
|
|
|
|
this._dragStart(t, e);
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
};
|
|
|
|
|
n.hasDragStarted = function (t) {
|
|
|
|
|
return Math.abs(t.x) > 3 || Math.abs(t.y) > 3;
|
|
|
|
|
};
|
|
|
|
|
n.pointerUp = function (t, e) {
|
|
|
|
|
this.emitEvent("pointerUp", [t, e]);
|
|
|
|
|
this._dragPointerUp(t, e);
|
|
|
|
|
};
|
|
|
|
|
n._dragPointerUp = function (t, e) {
|
|
|
|
|
if (this.isDragging) {
|
|
|
|
|
this._dragEnd(t, e);
|
|
|
|
|
} else {
|
|
|
|
|
this._staticClick(t, e);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
n._dragStart = function (t, e) {
|
|
|
|
|
this.isDragging = true;
|
|
|
|
|
this.isPreventingClicks = true;
|
|
|
|
|
this.dragStart(t, e);
|
|
|
|
|
};
|
|
|
|
|
n.dragStart = function (t, e) {
|
|
|
|
|
this.emitEvent("dragStart", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
n._dragMove = function (t, e, i) {
|
|
|
|
|
if (!this.isDragging) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.dragMove(t, e, i);
|
|
|
|
|
};
|
|
|
|
|
n.dragMove = function (t, e, i) {
|
|
|
|
|
t.preventDefault();
|
|
|
|
|
this.emitEvent("dragMove", [t, e, i]);
|
|
|
|
|
};
|
|
|
|
|
n._dragEnd = function (t, e) {
|
|
|
|
|
this.isDragging = false;
|
|
|
|
|
setTimeout(
|
|
|
|
|
function () {
|
|
|
|
|
delete this.isPreventingClicks;
|
|
|
|
|
}.bind(this)
|
|
|
|
|
);
|
|
|
|
|
this.dragEnd(t, e);
|
|
|
|
|
};
|
|
|
|
|
n.dragEnd = function (t, e) {
|
|
|
|
|
this.emitEvent("dragEnd", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
n.onclick = function (t) {
|
|
|
|
|
if (this.isPreventingClicks) {
|
|
|
|
|
t.preventDefault();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
n._staticClick = function (t, e) {
|
|
|
|
|
if (this.isIgnoringMouseUp && t.type == "mouseup") {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.staticClick(t, e);
|
|
|
|
|
if (t.type != "mouseup") {
|
|
|
|
|
this.isIgnoringMouseUp = true;
|
|
|
|
|
setTimeout(
|
|
|
|
|
function () {
|
|
|
|
|
delete this.isIgnoringMouseUp;
|
|
|
|
|
}.bind(this),
|
|
|
|
|
400
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
n.staticClick = function (t, e) {
|
|
|
|
|
this.emitEvent("staticClick", [t, e]);
|
|
|
|
|
};
|
|
|
|
|
i.getPointerPoint = e.getPointerPoint;
|
|
|
|
|
return i;
|
|
|
|
|
});
|
|
|
|
|
(function (i, n) {
|
|
|
|
|
i.Draggabilly = n(i, i.getSize, i.Unidragger);
|
|
|
|
|
})(window, function t(r, u, e) {
|
|
|
|
|
function i(t, e) {
|
|
|
|
|
for (var i in e) {
|
|
|
|
|
t[i] = e[i];
|
|
|
|
|
}
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
function n() {}
|
|
|
|
|
var o = r.jQuery;
|
|
|
|
|
function s(t, e) {
|
|
|
|
|
this.element = typeof t == "string" ? document.querySelector(t) : t;
|
|
|
|
|
if (o) {
|
|
|
|
|
this.$element = o(this.element);
|
|
|
|
|
}
|
|
|
|
|
this.options = i({}, this.constructor.defaults);
|
|
|
|
|
this.option(e);
|
|
|
|
|
this._create();
|
|
|
|
|
}
|
|
|
|
|
var a = (s.prototype = Object.create(e.prototype));
|
|
|
|
|
s.defaults = {};
|
|
|
|
|
a.option = function (t) {
|
|
|
|
|
i(this.options, t);
|
|
|
|
|
};
|
|
|
|
|
var h = { relative: true, absolute: true, fixed: true };
|
|
|
|
|
a._create = function () {
|
|
|
|
|
this.position = {};
|
|
|
|
|
this._getPosition();
|
|
|
|
|
this.startPoint = { x: 0, y: 0 };
|
|
|
|
|
this.dragPoint = { x: 0, y: 0 };
|
|
|
|
|
this.startPosition = i({}, this.position);
|
|
|
|
|
var t = getComputedStyle(this.element);
|
|
|
|
|
if (!h[t.position]) {
|
|
|
|
|
this.element.style.position = "relative";
|
|
|
|
|
}
|
|
|
|
|
this.on("pointerMove", this.onPointerMove);
|
|
|
|
|
this.on("pointerUp", this.onPointerUp);
|
|
|
|
|
this.enable();
|
|
|
|
|
this.setHandles();
|
|
|
|
|
};
|
|
|
|
|
a.setHandles = function () {
|
|
|
|
|
this.handles = this.options.handle ? this.element.querySelectorAll(this.options.handle) : [this.element];
|
|
|
|
|
this.bindHandles();
|
|
|
|
|
};
|
|
|
|
|
a.dispatchEvent = function (t, e, i) {
|
|
|
|
|
var n = [e].concat(i);
|
|
|
|
|
this.emitEvent(t, n);
|
|
|
|
|
this.dispatchJQueryEvent(t, e, i);
|
|
|
|
|
};
|
|
|
|
|
a.dispatchJQueryEvent = function (t, e, i) {
|
|
|
|
|
var n = r.jQuery;
|
|
|
|
|
if (!n || !this.$element) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var o = n.Event(e);
|
|
|
|
|
o.type = t;
|
|
|
|
|
this.$element.trigger(o, i);
|
|
|
|
|
};
|
|
|
|
|
a._getPosition = function () {
|
|
|
|
|
var t = getComputedStyle(this.element);
|
|
|
|
|
var e = this._getPositionCoord(t.left, "width");
|
|
|
|
|
var i = this._getPositionCoord(t.top, "height");
|
|
|
|
|
this.position.x = isNaN(e) ? 0 : e;
|
|
|
|
|
this.position.y = isNaN(i) ? 0 : i;
|
|
|
|
|
this._addTransformPosition(t);
|
|
|
|
|
};
|
|
|
|
|
a._getPositionCoord = function (t, e) {
|
|
|
|
|
if (t.indexOf("%") != -1) {
|
|
|
|
|
var i = u(this.element.parentNode);
|
|
|
|
|
return !i ? 0 : (parseFloat(t) / 100) * i[e];
|
|
|
|
|
}
|
|
|
|
|
return parseInt(t, 10);
|
|
|
|
|
};
|
|
|
|
|
a._addTransformPosition = function (t) {
|
|
|
|
|
var e = t.transform;
|
|
|
|
|
if (e.indexOf("matrix") !== 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var i = e.split(",");
|
|
|
|
|
var n = e.indexOf("matrix3d") === 0 ? 12 : 4;
|
|
|
|
|
var o = parseInt(i[n], 10);
|
|
|
|
|
var r = parseInt(i[n + 1], 10);
|
|
|
|
|
this.position.x += o;
|
|
|
|
|
this.position.y += r;
|
|
|
|
|
};
|
|
|
|
|
a.onPointerDown = function (t, e) {
|
|
|
|
|
this.element.classList.add("is-pointer-down");
|
|
|
|
|
this.dispatchJQueryEvent("pointerDown", t, [e]);
|
|
|
|
|
};
|
|
|
|
|
a.pointerDown = function (t, e) {
|
|
|
|
|
var i = this.okayPointerDown(t);
|
|
|
|
|
if (!i || !this.isEnabled) {
|
|
|
|
|
this._pointerReset();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.pointerDownPointer = { pageX: e.pageX, pageY: e.pageY };
|
|
|
|
|
t.preventDefault();
|
|
|
|
|
this.pointerDownBlur();
|
|
|
|
|
this._bindPostStartEvents(t);
|
|
|
|
|
this.element.classList.add("is-pointer-down");
|
|
|
|
|
this.dispatchEvent("pointerDown", t, [e]);
|
|
|
|
|
};
|
|
|
|
|
a.dragStart = function (t, e) {
|
|
|
|
|
if (!this.isEnabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this._getPosition();
|
|
|
|
|
this.measureContainment();
|
|
|
|
|
this.startPosition.x = this.position.x;
|
|
|
|
|
this.startPosition.y = this.position.y;
|
|
|
|
|
this.setLeftTop();
|
|
|
|
|
this.dragPoint.x = 0;
|
|
|
|
|
this.dragPoint.y = 0;
|
|
|
|
|
this.element.classList.add("is-dragging");
|
|
|
|
|
this.dispatchEvent("dragStart", t, [e]);
|
|
|
|
|
this.animate();
|
|
|
|
|
};
|
|
|
|
|
a.measureContainment = function () {
|
|
|
|
|
var t = this.getContainer();
|
|
|
|
|
if (!t) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var e = u(this.element);
|
|
|
|
|
var i = u(t);
|
|
|
|
|
var n = this.element.getBoundingClientRect();
|
|
|
|
|
var o = t.getBoundingClientRect();
|
|
|
|
|
var r = i.borderLeftWidth + i.borderRightWidth;
|
|
|
|
|
var s = i.borderTopWidth + i.borderBottomWidth;
|
|
|
|
|
var a = (this.relativeStartPosition = { x: n.left - (o.left + i.borderLeftWidth), y: n.top - (o.top + i.borderTopWidth) });
|
|
|
|
|
this.containSize = { width: i.width - r - a.x - e.width, height: i.height - s - a.y - e.height };
|
|
|
|
|
};
|
|
|
|
|
a.getContainer = function () {
|
|
|
|
|
var t = this.options.containment;
|
|
|
|
|
if (!t) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var e = t instanceof HTMLElement;
|
|
|
|
|
if (e) {
|
|
|
|
|
return t;
|
|
|
|
|
}
|
|
|
|
|
if (typeof t == "string") {
|
|
|
|
|
return document.querySelector(t);
|
|
|
|
|
}
|
|
|
|
|
return this.element.parentNode;
|
|
|
|
|
};
|
|
|
|
|
a.onPointerMove = function (t, e, i) {
|
|
|
|
|
this.dispatchJQueryEvent("pointerMove", t, [e, i]);
|
|
|
|
|
};
|
|
|
|
|
a.dragMove = function (t, e, i) {
|
|
|
|
|
if (!this.isEnabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
var n = i.x;
|
|
|
|
|
var o = i.y;
|
|
|
|
|
var r = this.options.grid;
|
|
|
|
|
var s = r && r[0];
|
|
|
|
|
var a = r && r[1];
|
|
|
|
|
n = d(n, s);
|
|
|
|
|
o = d(o, a);
|
|
|
|
|
n = this.containDrag("x", n, s);
|
|
|
|
|
o = this.containDrag("y", o, a);
|
|
|
|
|
n = this.options.axis == "y" ? 0 : n;
|
|
|
|
|
o = this.options.axis == "x" ? 0 : o;
|
|
|
|
|
this.position.x = this.startPosition.x + n;
|
|
|
|
|
this.position.y = this.startPosition.y + o;
|
|
|
|
|
this.dragPoint.x = n;
|
|
|
|
|
this.dragPoint.y = o;
|
|
|
|
|
this.dispatchEvent("dragMove", t, [e, i]);
|
|
|
|
|
};
|
|
|
|
|
function d(t, e, i) {
|
|
|
|
|
i = i || "round";
|
|
|
|
|
return e ? Math[i](t / e) * e : t;
|
|
|
|
|
}
|
|
|
|
|
a.containDrag = function (t, e, i) {
|
|
|
|
|
if (!this.options.containment) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
|
|
|
|
var n = t == "x" ? "width" : "height";
|
|
|
|
|
var o = this.relativeStartPosition[t];
|
|
|
|
|
var r = d(-o, i, "ceil");
|
|
|
|
|
var s = this.containSize[n];
|
|
|
|
|
s = d(s, i, "floor");
|
|
|
|
|
return Math.max(r, Math.min(s, e));
|
|
|
|
|
};
|
|
|
|
|
a.onPointerUp = function (t, e) {
|
|
|
|
|
this.element.classList.remove("is-pointer-down");
|
|
|
|
|
this.dispatchJQueryEvent("pointerUp", t, [e]);
|
|
|
|
|
};
|
|
|
|
|
a.dragEnd = function (t, e) {
|
|
|
|
|
if (!this.isEnabled) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.element.style.transform = "";
|
|
|
|
|
this.setLeftTop();
|
|
|
|
|
this.element.classList.remove("is-dragging");
|
|
|
|
|
this.dispatchEvent("dragEnd", t, [e]);
|
|
|
|
|
};
|
|
|
|
|
a.animate = function () {
|
|
|
|
|
if (!this.isDragging) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
this.positionDrag();
|
|
|
|
|
var e = this;
|
|
|
|
|
requestAnimationFrame(function t() {
|
|
|
|
|
e.animate();
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
a.setLeftTop = function () {
|
|
|
|
|
this.element.style.left = `${this.position.x}px`;
|
|
|
|
|
this.element.style.top = `${this.position.y}px`;
|
|
|
|
|
};
|
|
|
|
|
a.positionDrag = function () {
|
|
|
|
|
this.element.style.transform = `translate3d( ${this.dragPoint.x}px, ${this.dragPoint.y}px, 0)`;
|
|
|
|
|
};
|
|
|
|
|
a.staticClick = function (t, e) {
|
|
|
|
|
this.dispatchEvent("staticClick", t, [e]);
|
|
|
|
|
};
|
|
|
|
|
a.setPosition = function (t, e) {
|
|
|
|
|
this.position.x = t;
|
|
|
|
|
this.position.y = e;
|
|
|
|
|
this.setLeftTop();
|
|
|
|
|
};
|
|
|
|
|
a.enable = function () {
|
|
|
|
|
this.isEnabled = true;
|
|
|
|
|
};
|
|
|
|
|
a.disable = function () {
|
|
|
|
|
this.isEnabled = false;
|
|
|
|
|
if (this.isDragging) {
|
|
|
|
|
this.dragEnd();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
a.destroy = function () {
|
|
|
|
|
this.disable();
|
|
|
|
|
this.element.style.transform = "";
|
|
|
|
|
this.element.style.left = "";
|
|
|
|
|
this.element.style.top = "";
|
|
|
|
|
this.element.style.position = "";
|
|
|
|
|
this.unbindHandles();
|
|
|
|
|
if (this.$element) {
|
|
|
|
|
this.$element.removeData("draggabilly");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
a._init = n;
|
|
|
|
|
if (o && o.bridget) {
|
|
|
|
|
o.bridget("draggabilly", s);
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
});
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2019-05-11 19:44:58 +02:00
|
|
|
const Draggabilly = window.Draggabilly;
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2020-02-01 19:25:37 +01:00
|
|
|
const TAB_CONTAINER_MIN_WIDTH = 24;
|
|
|
|
|
const TAB_CONTAINER_MAX_WIDTH = 240;
|
2023-10-19 23:54:36 +02:00
|
|
|
const TAB_CONTAINER_LEFT_PADDING = 5;
|
2019-05-12 10:59:53 +02:00
|
|
|
const NEW_TAB_WIDTH = 32;
|
2019-12-23 11:52:45 +01:00
|
|
|
const MIN_FILLER_WIDTH = 50;
|
2021-05-23 21:24:22 +02:00
|
|
|
const MARGIN_WIDTH = 5;
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2019-05-11 19:44:58 +02:00
|
|
|
const TAB_SIZE_SMALL = 84;
|
|
|
|
|
const TAB_SIZE_SMALLER = 60;
|
|
|
|
|
const TAB_SIZE_MINI = 48;
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2020-01-12 20:15:05 +01:00
|
|
|
const TAB_TPL = `
|
2019-05-11 19:44:58 +02:00
|
|
|
<div class="note-tab">
|
|
|
|
|
<div class="note-tab-wrapper">
|
2021-10-12 22:36:22 +02:00
|
|
|
<div class="note-tab-drag-handle"></div>
|
2020-11-25 20:25:55 +01:00
|
|
|
<div class="note-tab-icon"></div>
|
2019-05-11 19:44:58 +02:00
|
|
|
<div class="note-tab-title"></div>
|
2025-01-09 18:07:02 +02:00
|
|
|
<div class="note-tab-close bx bx-x" title="${t("tab_row.close_tab")}" data-trigger-command="closeActiveTab"></div>
|
2019-05-11 19:44:58 +02:00
|
|
|
</div>
|
2019-05-12 10:11:41 +02:00
|
|
|
</div>`;
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
const NEW_TAB_BUTTON_TPL = `<div class="note-new-tab" data-trigger-command="openNewTab" title="${t("tab_row.add_new_tab")}">+</div>`;
|
2021-05-23 21:24:22 +02:00
|
|
|
const FILLER_TPL = `<div class="tab-row-filler"></div>`;
|
2019-05-12 10:59:53 +02:00
|
|
|
|
2020-01-12 20:15:05 +01:00
|
|
|
const TAB_ROW_TPL = `
|
2021-06-13 22:55:31 +02:00
|
|
|
<div class="tab-row-widget">
|
2020-01-12 20:15:05 +01:00
|
|
|
<style>
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget {
|
2020-01-12 20:15:05 +01:00
|
|
|
box-sizing: border-box;
|
|
|
|
|
position: relative;
|
|
|
|
|
width: 100%;
|
|
|
|
|
background: var(--main-background-color);
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
2024-11-22 21:41:23 +02:00
|
|
|
|
|
|
|
|
.tab-row-widget.full-width {
|
|
|
|
|
background: var(--launcher-pane-background-color);
|
|
|
|
|
}
|
2020-08-27 22:03:56 +02:00
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget * {
|
2020-01-12 20:15:05 +01:00
|
|
|
box-sizing: inherit;
|
|
|
|
|
font: inherit;
|
|
|
|
|
}
|
2020-08-27 22:03:56 +02:00
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .tab-row-widget-container {
|
2020-08-27 22:03:56 +02:00
|
|
|
box-sizing: border-box;
|
2020-01-12 20:15:05 +01:00
|
|
|
position: relative;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
}
|
2020-08-27 22:03:56 +02:00
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab {
|
2020-01-12 20:15:05 +01:00
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
|
|
|
|
width: 240px;
|
|
|
|
|
border: 0;
|
|
|
|
|
margin: 0;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
pointer-events: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note-new-tab {
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
2021-06-02 21:23:40 +02:00
|
|
|
width: 36px;
|
|
|
|
|
height: 36px;
|
|
|
|
|
padding: 1px;
|
2020-01-12 20:15:05 +01:00
|
|
|
border: 0;
|
|
|
|
|
margin: 0;
|
|
|
|
|
z-index: 1;
|
|
|
|
|
text-align: center;
|
|
|
|
|
font-size: 24px;
|
|
|
|
|
cursor: pointer;
|
2020-08-27 22:03:56 +02:00
|
|
|
box-sizing: border-box;
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.note-new-tab:hover {
|
|
|
|
|
background-color: var(--accented-background-color);
|
2022-09-18 13:52:19 +02:00
|
|
|
border-radius: var(--button-border-radius);
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-row-filler {
|
2020-08-27 22:03:56 +02:00
|
|
|
box-sizing: border-box;
|
2020-01-12 20:15:05 +01:00
|
|
|
-webkit-app-region: drag;
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
2021-06-26 13:35:36 +02:00
|
|
|
height: 100%;
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
2021-05-23 21:24:22 +02:00
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[active] {
|
2020-01-12 20:15:05 +01:00
|
|
|
z-index: 5;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab,
|
|
|
|
|
.tab-row-widget .note-tab * {
|
2020-01-12 20:15:05 +01:00
|
|
|
cursor: default;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab.note-tab-was-just-added {
|
2020-01-12 20:15:05 +01:00
|
|
|
top: 10px;
|
|
|
|
|
animation: note-tab-was-just-added 120ms forwards ease-in-out;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab .note-tab-wrapper {
|
2020-01-12 20:15:05 +01:00
|
|
|
position: absolute;
|
|
|
|
|
display: flex;
|
2023-01-16 22:28:55 +01:00
|
|
|
align-items: center;
|
2020-01-12 20:15:05 +01:00
|
|
|
top: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
left: 0;
|
|
|
|
|
right: 0;
|
2021-06-01 23:19:49 +02:00
|
|
|
height: 36px;
|
2021-07-04 15:49:52 +02:00
|
|
|
padding: 7px 5px 7px 11px;
|
2021-05-23 21:24:22 +02:00
|
|
|
border-radius: 8px;
|
2020-01-12 20:15:05 +01:00
|
|
|
overflow: hidden;
|
|
|
|
|
pointer-events: all;
|
2021-06-02 21:23:40 +02:00
|
|
|
color: var(--inactive-tab-text-color);
|
2024-12-03 00:04:12 +02:00
|
|
|
--tab-background-color: var(--workspace-tab-background-color);
|
2024-12-19 09:04:53 +02:00
|
|
|
background-color: var(--tab-background-color, var(--inactive-tab-background-color));
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[active] .note-tab-wrapper {
|
2020-01-12 20:15:05 +01:00
|
|
|
font-weight: bold;
|
2021-06-02 21:23:40 +02:00
|
|
|
color: var(--active-tab-text-color);
|
2024-12-03 00:04:12 +02:00
|
|
|
background-color : var(--tab-background-color, var(--active-tab-background-color));
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[is-mini] .note-tab-wrapper {
|
2020-01-12 20:15:05 +01:00
|
|
|
padding-left: 2px;
|
|
|
|
|
padding-right: 2px;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab .note-tab-title {
|
2020-01-12 20:15:05 +01:00
|
|
|
flex: 1;
|
|
|
|
|
vertical-align: top;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab .note-tab-icon {
|
2020-11-25 20:25:55 +01:00
|
|
|
position: relative;
|
|
|
|
|
top: -1px;
|
|
|
|
|
padding-right: 3px;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[is-small] .note-tab-title {
|
2020-01-12 20:15:05 +01:00
|
|
|
margin-left: 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab .note-tab-drag-handle {
|
2020-01-12 20:15:05 +01:00
|
|
|
position: absolute;
|
|
|
|
|
top: 0;
|
|
|
|
|
bottom: 0;
|
|
|
|
|
right: 0;
|
|
|
|
|
left: 0;
|
2024-12-20 08:24:54 +02:00
|
|
|
z-index: 50;
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab .note-tab-close {
|
2023-01-16 22:28:55 +01:00
|
|
|
flex: 0 0 22px;
|
2020-01-12 20:15:05 +01:00
|
|
|
border-radius: 50%;
|
|
|
|
|
z-index: 100;
|
2021-07-04 15:49:52 +02:00
|
|
|
width: 22px;
|
2023-01-16 22:28:55 +01:00
|
|
|
height: 22px;
|
2021-10-06 18:31:19 +02:00
|
|
|
cursor: pointer;
|
2023-01-16 22:28:55 +01:00
|
|
|
text-align: center;
|
2020-01-12 20:15:05 +01:00
|
|
|
}
|
2021-12-05 12:07:53 +00:00
|
|
|
|
|
|
|
|
.tab-row-widget .note-tab:hover .note-tab-wrapper {
|
2024-12-03 00:04:12 +02:00
|
|
|
background-color: var(--tab-background-color, var(--inactive-tab-hover-background-color));
|
2021-12-05 12:07:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.tab-row-widget .note-tab[active]:hover .note-tab-wrapper {
|
2024-12-03 00:04:12 +02:00
|
|
|
background-color: var(--tab-background-color, var(--active-tab-hover-background-color));
|
2021-12-05 12:07:53 +00:00
|
|
|
}
|
2020-01-12 20:15:05 +01:00
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab .note-tab-close:hover {
|
2020-01-12 20:15:05 +01:00
|
|
|
background-color: var(--hover-item-background-color);
|
|
|
|
|
color: var(--hover-item-text-color);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[is-smaller] .note-tab-close {
|
2020-01-12 20:15:05 +01:00
|
|
|
margin-left: auto;
|
|
|
|
|
}
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[is-mini]:not([active]) .note-tab-close {
|
2020-01-12 20:15:05 +01:00
|
|
|
display: none;
|
|
|
|
|
}
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget .note-tab[is-mini][active] .note-tab-close {
|
2020-01-12 20:15:05 +01:00
|
|
|
margin-left: auto;
|
|
|
|
|
margin-right: auto;
|
|
|
|
|
}
|
|
|
|
|
@-moz-keyframes note-tab-was-just-added {
|
|
|
|
|
to {
|
|
|
|
|
top: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@-webkit-keyframes note-tab-was-just-added {
|
|
|
|
|
to {
|
|
|
|
|
top: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@-o-keyframes note-tab-was-just-added {
|
|
|
|
|
to {
|
|
|
|
|
top: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@keyframes note-tab-was-just-added {
|
|
|
|
|
to {
|
|
|
|
|
top: 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-13 22:55:31 +02:00
|
|
|
.tab-row-widget.tab-row-widget-is-sorting .note-tab:not(.note-tab-is-dragging),
|
|
|
|
|
.tab-row-widget:not(.tab-row-widget-is-sorting) .note-tab.note-tab-was-just-dragged {
|
2020-01-12 20:15:05 +01:00
|
|
|
transition: transform 120ms ease-in-out;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|
2021-06-13 22:55:31 +02:00
|
|
|
<div class="tab-row-widget-container"></div>
|
2020-01-12 19:05:09 +01:00
|
|
|
</div>`;
|
|
|
|
|
|
|
|
|
|
export default class TabRowWidget extends BasicWidget {
|
2020-01-12 20:15:05 +01:00
|
|
|
doRender() {
|
2020-01-15 22:11:30 +01:00
|
|
|
this.$widget = $(TAB_ROW_TPL);
|
2025-01-09 18:07:02 +02:00
|
|
|
|
2024-12-02 23:30:52 +02:00
|
|
|
const documentStyle = window.getComputedStyle(document.documentElement);
|
2025-01-09 18:07:02 +02:00
|
|
|
this.showNoteIcons = documentStyle.getPropertyValue("--tab-note-icons") === "true";
|
2020-01-12 19:05:09 +01:00
|
|
|
|
2019-05-11 21:27:27 +02:00
|
|
|
this.draggabillies = [];
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2020-01-15 22:11:30 +01:00
|
|
|
this.setupStyle();
|
2019-05-11 19:44:58 +02:00
|
|
|
this.setupEvents();
|
|
|
|
|
this.setupDraggabilly();
|
2019-05-12 10:59:53 +02:00
|
|
|
this.setupNewButton();
|
2019-11-17 10:22:26 +01:00
|
|
|
this.setupFiller();
|
|
|
|
|
this.layoutTabs();
|
2019-05-11 19:44:58 +02:00
|
|
|
this.setVisibility();
|
2019-05-11 21:27:27 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
this.$widget.on("contextmenu", ".note-tab", (e) => {
|
2020-01-12 19:05:09 +01:00
|
|
|
e.preventDefault();
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
const ntxId = $(e.target).closest(".note-tab").attr("data-ntx-id");
|
2020-01-12 19:05:09 +01:00
|
|
|
|
2020-02-29 13:03:05 +01:00
|
|
|
contextMenu.show({
|
|
|
|
|
x: e.pageX,
|
|
|
|
|
y: e.pageY,
|
|
|
|
|
items: [
|
2025-01-09 18:07:02 +02:00
|
|
|
{ title: t("tab_row.close"), command: "closeTab", uiIcon: "bx bx-x" },
|
|
|
|
|
{ title: t("tab_row.close_other_tabs"), command: "closeOtherTabs", uiIcon: "bx bx-empty", enabled: appContext.tabManager.noteContexts.length !== 1 },
|
|
|
|
|
{ title: t("tab_row.close_right_tabs"), command: "closeRightTabs", uiIcon: "bx bx-empty", enabled: appContext.tabManager.noteContexts.at(-1).ntxId !== ntxId },
|
|
|
|
|
{ title: t("tab_row.close_all_tabs"), command: "closeAllTabs", uiIcon: "bx bx-empty" },
|
|
|
|
|
|
|
|
|
|
{ title: "----" },
|
2024-11-20 14:39:19 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
{ title: t("tab_row.reopen_last_tab"), command: "reopenLastTab", uiIcon: "bx bx-undo", enabled: appContext.tabManager.recentlyClosedTabs.length !== 0 },
|
2024-11-22 17:24:06 +08:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
{ title: "----" },
|
2024-11-22 17:24:06 +08:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
{ title: t("tab_row.move_tab_to_new_window"), command: "moveTabToNewWindow", uiIcon: "bx bx-window-open" },
|
|
|
|
|
{ title: t("tab_row.copy_tab_to_new_window"), command: "copyTabToNewWindow", uiIcon: "bx bx-empty" }
|
2024-11-20 14:39:19 +02:00
|
|
|
],
|
2025-01-09 18:07:02 +02:00
|
|
|
selectMenuItemHandler: ({ command }) => {
|
|
|
|
|
this.triggerCommand(command, { ntxId });
|
2020-01-12 19:05:09 +01:00
|
|
|
}
|
|
|
|
|
});
|
2020-01-12 20:15:05 +01:00
|
|
|
});
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-15 22:11:30 +01:00
|
|
|
setupStyle() {
|
|
|
|
|
this.$style = $("<style>");
|
|
|
|
|
this.$widget.append(this.$style);
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setupEvents() {
|
2025-01-09 18:07:02 +02:00
|
|
|
const resizeListener = (_) => {
|
2019-05-11 19:44:58 +02:00
|
|
|
this.cleanUpPreviouslyDraggedTabs();
|
|
|
|
|
this.layoutTabs();
|
2019-07-20 22:01:50 +02:00
|
|
|
};
|
|
|
|
|
|
2023-04-06 21:30:37 +02:00
|
|
|
new ResizeObserver(resizeListener).observe(this.$widget[0]);
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2020-02-16 19:54:11 +01:00
|
|
|
this.tabEls.forEach((tabEl) => this.setTabCloseEvent(tabEl));
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-07 22:14:35 +02:00
|
|
|
setVisibility() {
|
2020-01-15 22:11:30 +01:00
|
|
|
this.$widget.show();
|
2019-05-07 22:14:35 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-30 22:31:12 +02:00
|
|
|
get tabEls() {
|
2025-01-09 18:07:02 +02:00
|
|
|
return Array.prototype.slice.call(this.$widget.find(".note-tab"));
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-01 19:25:37 +01:00
|
|
|
get $tabContainer() {
|
2025-01-09 18:07:02 +02:00
|
|
|
return this.$widget.find(".tab-row-widget-container");
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2020-02-01 19:25:37 +01:00
|
|
|
get tabWidths() {
|
2019-05-11 19:44:58 +02:00
|
|
|
const numberOfTabs = this.tabEls.length;
|
2020-02-01 19:25:37 +01:00
|
|
|
const tabsContainerWidth = this.$tabContainer[0].clientWidth - NEW_TAB_WIDTH - MIN_FILLER_WIDTH;
|
2021-05-23 21:24:22 +02:00
|
|
|
const marginWidth = (numberOfTabs - 1) * MARGIN_WIDTH;
|
|
|
|
|
const targetWidth = (tabsContainerWidth - marginWidth) / numberOfTabs;
|
2020-02-01 19:25:37 +01:00
|
|
|
const clampedTargetWidth = Math.max(TAB_CONTAINER_MIN_WIDTH, Math.min(TAB_CONTAINER_MAX_WIDTH, targetWidth));
|
2019-05-11 19:44:58 +02:00
|
|
|
const flooredClampedTargetWidth = Math.floor(clampedTargetWidth);
|
2021-05-23 21:24:22 +02:00
|
|
|
const totalTabsWidthUsingTarget = flooredClampedTargetWidth * numberOfTabs + marginWidth;
|
2020-02-01 19:25:37 +01:00
|
|
|
const totalExtraWidthDueToFlooring = tabsContainerWidth - totalTabsWidthUsingTarget;
|
2019-05-11 19:44:58 +02:00
|
|
|
|
|
|
|
|
const widths = [];
|
|
|
|
|
let extraWidthRemaining = totalExtraWidthDueToFlooring;
|
2019-11-17 10:22:26 +01:00
|
|
|
|
2019-05-11 19:44:58 +02:00
|
|
|
for (let i = 0; i < numberOfTabs; i += 1) {
|
2020-02-01 19:25:37 +01:00
|
|
|
const extraWidth = flooredClampedTargetWidth < TAB_CONTAINER_MAX_WIDTH && extraWidthRemaining > 0 ? 1 : 0;
|
2021-05-23 21:24:22 +02:00
|
|
|
|
2019-05-11 19:44:58 +02:00
|
|
|
widths.push(flooredClampedTargetWidth + extraWidth);
|
2021-05-23 21:24:22 +02:00
|
|
|
|
|
|
|
|
if (extraWidthRemaining > 0) {
|
|
|
|
|
extraWidthRemaining -= 1;
|
|
|
|
|
}
|
2019-05-11 19:44:58 +02:00
|
|
|
}
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2020-01-15 22:35:15 +01:00
|
|
|
if (this.$filler) {
|
2022-12-21 15:19:05 +01:00
|
|
|
this.$filler.css("width", `${extraWidthRemaining + MIN_FILLER_WIDTH}px`);
|
2019-11-17 10:22:26 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-12 10:11:41 +02:00
|
|
|
return widths;
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2019-05-12 10:59:53 +02:00
|
|
|
getTabPositions() {
|
|
|
|
|
const tabPositions = [];
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2023-10-19 23:54:36 +02:00
|
|
|
let position = TAB_CONTAINER_LEFT_PADDING;
|
2025-01-09 18:07:02 +02:00
|
|
|
this.tabWidths.forEach((width) => {
|
2019-05-12 10:59:53 +02:00
|
|
|
tabPositions.push(position);
|
2021-05-23 21:24:22 +02:00
|
|
|
position += width + MARGIN_WIDTH;
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2023-06-30 11:18:34 +02:00
|
|
|
position -= MARGIN_WIDTH; // the last margin should not be applied
|
2021-05-23 21:24:22 +02:00
|
|
|
|
2019-05-12 10:59:53 +02:00
|
|
|
const newTabPosition = position;
|
2019-11-17 10:22:26 +01:00
|
|
|
const fillerPosition = position + 32;
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
return { tabPositions, newTabPosition, fillerPosition };
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
layoutTabs() {
|
2020-02-01 19:25:37 +01:00
|
|
|
const tabContainerWidths = this.tabWidths;
|
2019-05-11 19:44:58 +02:00
|
|
|
|
|
|
|
|
this.tabEls.forEach((tabEl, i) => {
|
2020-02-01 19:25:37 +01:00
|
|
|
const width = tabContainerWidths[i];
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2022-12-21 15:19:05 +01:00
|
|
|
tabEl.style.width = `${width}px`;
|
2025-01-09 18:07:02 +02:00
|
|
|
tabEl.removeAttribute("is-small");
|
|
|
|
|
tabEl.removeAttribute("is-smaller");
|
|
|
|
|
tabEl.removeAttribute("is-mini");
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
if (width < TAB_SIZE_SMALL) tabEl.setAttribute("is-small", "");
|
|
|
|
|
if (width < TAB_SIZE_SMALLER) tabEl.setAttribute("is-smaller", "");
|
|
|
|
|
if (width < TAB_SIZE_MINI) tabEl.setAttribute("is-mini", "");
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
let styleHTML = "";
|
2019-05-12 10:59:53 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
const { tabPositions, newTabPosition, fillerPosition } = this.getTabPositions();
|
2019-05-12 10:59:53 +02:00
|
|
|
|
|
|
|
|
tabPositions.forEach((position, i) => {
|
2025-01-09 18:07:02 +02:00
|
|
|
styleHTML += `.note-tab:nth-child(${i + 1}) { transform: translate3d(${position}px, 0, 0)} `;
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
styleHTML += `.note-new-tab { transform: translate3d(${newTabPosition}px, 0, 0) } `;
|
|
|
|
|
styleHTML += `.tab-row-filler { transform: translate3d(${fillerPosition}px, 0, 0) } `;
|
2019-05-12 10:59:53 +02:00
|
|
|
|
2020-01-15 22:11:30 +01:00
|
|
|
this.$style.html(styleHTML);
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
addTab(ntxId) {
|
2025-01-09 18:07:02 +02:00
|
|
|
const $tab = $(TAB_TPL).attr("data-ntx-id", ntxId);
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2020-01-20 22:35:52 +01:00
|
|
|
keyboardActionService.updateDisplayedShortcuts($tab);
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
$tab.addClass("note-tab-was-just-added");
|
2020-01-20 22:35:52 +01:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
setTimeout(() => $tab.removeClass("note-tab-was-just-added"), 500);
|
2020-01-20 22:35:52 +01:00
|
|
|
|
|
|
|
|
this.$newTab.before($tab);
|
2019-05-11 19:44:58 +02:00
|
|
|
this.setVisibility();
|
2020-02-16 19:54:11 +01:00
|
|
|
this.setTabCloseEvent($tab);
|
2025-01-09 18:07:02 +02:00
|
|
|
this.updateTitle($tab, t("tab_row.new_tab"));
|
2019-05-11 19:44:58 +02:00
|
|
|
this.cleanUpPreviouslyDraggedTabs();
|
|
|
|
|
this.layoutTabs();
|
|
|
|
|
this.setupDraggabilly();
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
closeActiveTabCommand({ $el }) {
|
|
|
|
|
const ntxId = $el.closest(".note-tab").attr("data-ntx-id");
|
2020-05-05 23:58:52 +02:00
|
|
|
|
2021-05-22 12:35:41 +02:00
|
|
|
appContext.tabManager.removeNoteContext(ntxId);
|
2020-05-05 23:58:52 +02:00
|
|
|
}
|
2019-05-15 21:50:27 +02:00
|
|
|
|
2020-05-05 23:58:52 +02:00
|
|
|
setTabCloseEvent($tab) {
|
2025-01-09 18:07:02 +02:00
|
|
|
$tab.on("mousedown", (e) => {
|
2019-05-15 21:50:27 +02:00
|
|
|
if (e.which === 2) {
|
2025-01-09 18:07:02 +02:00
|
|
|
appContext.tabManager.removeNoteContext($tab.attr("data-ntx-id"));
|
2019-05-15 21:50:27 +02:00
|
|
|
|
|
|
|
|
return true; // event has been handled
|
|
|
|
|
}
|
|
|
|
|
});
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get activeTabEl() {
|
2025-01-09 18:07:02 +02:00
|
|
|
return this.$widget.find(".note-tab[active]")[0];
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-22 17:58:46 +02:00
|
|
|
activeContextChangedEvent() {
|
2021-05-22 12:35:41 +02:00
|
|
|
let activeNoteContext = appContext.tabManager.getActiveContext();
|
2020-02-09 21:13:05 +01:00
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
if (!activeNoteContext) {
|
2020-03-07 20:41:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
if (activeNoteContext.mainNtxId) {
|
|
|
|
|
activeNoteContext = appContext.tabManager.getNoteContextById(activeNoteContext.mainNtxId);
|
2021-05-19 23:00:03 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
const tabEl = this.getTabById(activeNoteContext.ntxId)[0];
|
2019-05-11 19:44:58 +02:00
|
|
|
const activeTabEl = this.activeTabEl;
|
|
|
|
|
if (activeTabEl === tabEl) return;
|
2025-01-09 18:07:02 +02:00
|
|
|
if (activeTabEl) activeTabEl.removeAttribute("active");
|
|
|
|
|
if (tabEl) tabEl.setAttribute("active", "");
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
newNoteContextCreatedEvent({ noteContext }) {
|
2021-05-22 12:26:45 +02:00
|
|
|
if (!noteContext.mainNtxId) {
|
|
|
|
|
this.addTab(noteContext.ntxId);
|
2021-05-19 23:00:03 +02:00
|
|
|
}
|
2020-01-20 20:51:22 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
removeTab(ntxId) {
|
|
|
|
|
const tabEl = this.getTabById(ntxId)[0];
|
2020-01-15 22:27:52 +01:00
|
|
|
|
2020-03-10 22:25:57 +01:00
|
|
|
if (tabEl) {
|
|
|
|
|
tabEl.parentNode.removeChild(tabEl);
|
|
|
|
|
this.cleanUpPreviouslyDraggedTabs();
|
|
|
|
|
this.layoutTabs();
|
|
|
|
|
this.setupDraggabilly();
|
|
|
|
|
this.setVisibility();
|
|
|
|
|
}
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-24 21:43:24 +02:00
|
|
|
getNtxIdsInOrder() {
|
2025-01-09 18:07:02 +02:00
|
|
|
return this.tabEls.map((el) => el.getAttribute("data-ntx-id"));
|
2019-05-07 21:34:01 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-20 22:35:52 +01:00
|
|
|
updateTitle($tab, title) {
|
2025-01-09 18:07:02 +02:00
|
|
|
$tab.attr("title", title);
|
|
|
|
|
$tab.find(".note-tab-title").text(title);
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
getTabById(ntxId) {
|
2021-05-24 21:43:24 +02:00
|
|
|
return this.$widget.find(`[data-ntx-id='${ntxId}']`);
|
2020-01-19 18:05:06 +01:00
|
|
|
}
|
|
|
|
|
|
2020-11-24 23:24:05 +01:00
|
|
|
getTabId($tab) {
|
2025-01-09 18:07:02 +02:00
|
|
|
return $tab.attr("data-ntx-id");
|
2020-11-24 23:24:05 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
noteContextRemovedEvent({ ntxIds }) {
|
2021-05-22 12:26:45 +02:00
|
|
|
for (const ntxId of ntxIds) {
|
|
|
|
|
this.removeTab(ntxId);
|
2021-05-20 23:13:34 +02:00
|
|
|
}
|
2020-01-19 21:12:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-30 22:31:12 +02:00
|
|
|
cleanUpPreviouslyDraggedTabs() {
|
2025-01-09 18:07:02 +02:00
|
|
|
this.tabEls.forEach((tabEl) => tabEl.classList.remove("note-tab-was-just-dragged"));
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setupDraggabilly() {
|
2019-05-11 19:44:58 +02:00
|
|
|
const tabEls = this.tabEls;
|
2025-01-09 18:07:02 +02:00
|
|
|
const { tabPositions } = this.getTabPositions();
|
2019-05-11 19:44:58 +02:00
|
|
|
|
|
|
|
|
if (this.isDragging) {
|
|
|
|
|
this.isDragging = false;
|
2025-01-09 18:07:02 +02:00
|
|
|
this.$widget.removeClass("tab-row-widget-is-sorting");
|
|
|
|
|
this.draggabillyDragging.element.classList.remove("note-tab-is-dragging");
|
|
|
|
|
this.draggabillyDragging.element.style.transform = "";
|
2019-05-11 19:44:58 +02:00
|
|
|
this.draggabillyDragging.dragEnd();
|
|
|
|
|
this.draggabillyDragging.isDragging = false;
|
2025-01-09 18:07:02 +02:00
|
|
|
this.draggabillyDragging.positionDrag = (_) => {}; // Prevent Draggabilly from updating tabEl.style.transform in later frames
|
2019-05-11 19:44:58 +02:00
|
|
|
this.draggabillyDragging.destroy();
|
|
|
|
|
this.draggabillyDragging = null;
|
|
|
|
|
}
|
2019-04-30 22:31:12 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
this.draggabillies.forEach((d) => d.destroy());
|
2019-05-11 19:44:58 +02:00
|
|
|
|
|
|
|
|
tabEls.forEach((tabEl, originalIndex) => {
|
|
|
|
|
const originalTabPositionX = tabPositions[originalIndex];
|
|
|
|
|
const draggabilly = new Draggabilly(tabEl, {
|
2025-01-09 18:07:02 +02:00
|
|
|
axis: "x",
|
|
|
|
|
handle: ".note-tab-drag-handle",
|
2020-02-01 19:25:37 +01:00
|
|
|
containment: this.$tabContainer[0]
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.draggabillies.push(draggabilly);
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
draggabilly.on("pointerDown", (_) => {
|
|
|
|
|
appContext.tabManager.activateNoteContext(tabEl.getAttribute("data-ntx-id"));
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
draggabilly.on("dragStart", (_) => {
|
2019-05-11 19:44:58 +02:00
|
|
|
this.isDragging = true;
|
|
|
|
|
this.draggabillyDragging = draggabilly;
|
2025-01-09 18:07:02 +02:00
|
|
|
tabEl.classList.add("note-tab-is-dragging");
|
|
|
|
|
this.$widget.addClass("tab-row-widget-is-sorting");
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
draggabilly.on("dragEnd", (_) => {
|
2019-05-11 19:44:58 +02:00
|
|
|
this.isDragging = false;
|
2023-05-05 23:17:23 +02:00
|
|
|
const finalTranslateX = parseFloat(tabEl.style.left);
|
2019-05-11 19:44:58 +02:00
|
|
|
tabEl.style.transform = `translate3d(0, 0, 0)`;
|
|
|
|
|
|
|
|
|
|
// Animate dragged tab back into its place
|
2025-01-09 18:07:02 +02:00
|
|
|
requestAnimationFrame((_) => {
|
|
|
|
|
tabEl.style.left = "0";
|
|
|
|
|
tabEl.style.transform = `translate3d(${finalTranslateX}px, 0, 0)`;
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
requestAnimationFrame((_) => {
|
|
|
|
|
tabEl.classList.remove("note-tab-is-dragging");
|
|
|
|
|
this.$widget.removeClass("tab-row-widget-is-sorting");
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
tabEl.classList.add("note-tab-was-just-dragged");
|
2019-05-11 19:44:58 +02:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
requestAnimationFrame((_) => {
|
|
|
|
|
tabEl.style.transform = "";
|
2019-05-11 19:44:58 +02:00
|
|
|
|
|
|
|
|
this.layoutTabs();
|
|
|
|
|
this.setupDraggabilly();
|
2025-01-09 18:07:02 +02:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
2019-05-11 19:44:58 +02:00
|
|
|
});
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
draggabilly.on("dragMove", (event, pointer, moveVector) => {
|
2023-06-30 11:18:34 +02:00
|
|
|
// The current index be computed within the event since it can change during the dragMove
|
2019-05-11 19:44:58 +02:00
|
|
|
const tabEls = this.tabEls;
|
|
|
|
|
const currentIndex = tabEls.indexOf(tabEl);
|
|
|
|
|
|
|
|
|
|
const currentTabPositionX = originalTabPositionX + moveVector.x;
|
2019-05-12 10:59:53 +02:00
|
|
|
const destinationIndexTarget = this.closest(currentTabPositionX, tabPositions);
|
2019-05-11 19:44:58 +02:00
|
|
|
const destinationIndex = Math.max(0, Math.min(tabEls.length, destinationIndexTarget));
|
|
|
|
|
|
|
|
|
|
if (currentIndex !== destinationIndex) {
|
|
|
|
|
this.animateTabMove(tabEl, currentIndex, destinationIndex);
|
|
|
|
|
}
|
2021-03-21 23:35:13 +01:00
|
|
|
|
|
|
|
|
if (Math.abs(moveVector.y) > 100) {
|
2025-01-09 18:07:02 +02:00
|
|
|
this.triggerCommand("moveTabToNewWindow", { ntxId: this.getTabId($(tabEl)) });
|
2021-03-21 23:35:13 +01:00
|
|
|
}
|
2020-02-01 22:29:32 +01:00
|
|
|
});
|
|
|
|
|
});
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
|
|
|
|
|
2020-01-15 22:27:52 +01:00
|
|
|
animateTabMove(tabEl, originIndex, destinationIndex) {
|
2019-05-11 19:44:58 +02:00
|
|
|
if (destinationIndex < originIndex) {
|
|
|
|
|
tabEl.parentNode.insertBefore(tabEl, this.tabEls[destinationIndex]);
|
|
|
|
|
} else {
|
2020-01-20 20:51:22 +01:00
|
|
|
const beforeEl = this.tabEls[destinationIndex + 1] || this.$newTab[0];
|
2019-05-22 21:59:14 +02:00
|
|
|
|
|
|
|
|
tabEl.parentNode.insertBefore(tabEl, beforeEl);
|
2019-05-11 19:44:58 +02:00
|
|
|
}
|
2025-01-09 18:07:02 +02:00
|
|
|
this.triggerEvent("tabReorder", { ntxIdsInOrder: this.getNtxIdsInOrder() });
|
2019-05-11 19:44:58 +02:00
|
|
|
this.layoutTabs();
|
2019-04-30 22:31:12 +02:00
|
|
|
}
|
2019-05-12 10:59:53 +02:00
|
|
|
|
|
|
|
|
setupNewButton() {
|
2020-01-15 22:35:15 +01:00
|
|
|
this.$newTab = $(NEW_TAB_BUTTON_TPL);
|
2019-05-12 10:59:53 +02:00
|
|
|
|
2020-02-01 19:25:37 +01:00
|
|
|
this.$tabContainer.append(this.$newTab);
|
2019-05-12 10:59:53 +02:00
|
|
|
}
|
|
|
|
|
|
2019-11-17 10:22:26 +01:00
|
|
|
setupFiller() {
|
2020-01-15 22:35:15 +01:00
|
|
|
this.$filler = $(FILLER_TPL);
|
2019-11-17 10:22:26 +01:00
|
|
|
|
2020-02-01 19:25:37 +01:00
|
|
|
this.$tabContainer.append(this.$filler);
|
2019-11-17 10:22:26 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-12 10:59:53 +02:00
|
|
|
closest(value, array) {
|
|
|
|
|
let closest = Infinity;
|
|
|
|
|
let closestIndex = -1;
|
|
|
|
|
|
|
|
|
|
array.forEach((v, i) => {
|
|
|
|
|
if (Math.abs(value - v) < closest) {
|
|
|
|
|
closest = Math.abs(value - v);
|
2020-02-01 22:29:32 +01:00
|
|
|
closestIndex = i;
|
2019-05-12 10:59:53 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return closestIndex;
|
2025-01-09 18:07:02 +02:00
|
|
|
}
|
2020-01-19 21:24:14 +01:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
noteSwitchedAndActivatedEvent({ noteContext }) {
|
2021-05-22 17:58:46 +02:00
|
|
|
this.activeContextChangedEvent();
|
2020-02-28 11:46:35 +01:00
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
this.updateTabById(noteContext.mainNtxId || noteContext.ntxId);
|
2020-02-28 00:31:12 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
noteSwitchedEvent({ noteContext }) {
|
2021-05-22 12:26:45 +02:00
|
|
|
this.updateTabById(noteContext.mainNtxId || noteContext.ntxId);
|
2020-02-28 00:31:12 +01:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
noteContextReorderEvent({ oldMainNtxId, newMainNtxId }) {
|
2023-06-01 00:48:37 +08:00
|
|
|
if (!oldMainNtxId || !newMainNtxId) {
|
|
|
|
|
// no need to update tab row
|
2023-05-31 01:53:55 +08:00
|
|
|
return;
|
2023-06-01 00:48:37 +08:00
|
|
|
}
|
2023-05-31 01:53:55 +08:00
|
|
|
|
2023-06-01 00:48:37 +08:00
|
|
|
// update tab id for the new main context
|
|
|
|
|
this.getTabById(oldMainNtxId).attr("data-ntx-id", newMainNtxId);
|
2023-10-19 23:54:36 +02:00
|
|
|
this.updateTabById(newMainNtxId);
|
2023-05-31 01:53:55 +08:00
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
contextsReopenedEvent({ mainNtxId, tabPosition }) {
|
2023-06-03 05:54:33 +08:00
|
|
|
if (mainNtxId === undefined || tabPosition === undefined) {
|
|
|
|
|
// no tab reopened
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const tabEl = this.getTabById(mainNtxId)[0];
|
|
|
|
|
tabEl.parentNode.insertBefore(tabEl, this.tabEls[tabPosition]);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
updateTabById(ntxId) {
|
|
|
|
|
const $tab = this.getTabById(ntxId);
|
2020-01-19 21:24:14 +01:00
|
|
|
|
2023-02-14 16:06:49 +01:00
|
|
|
const noteContext = appContext.tabManager.getNoteContextById(ntxId);
|
2020-01-19 21:24:14 +01:00
|
|
|
|
2023-02-14 16:06:49 +01:00
|
|
|
this.updateTab($tab, noteContext);
|
2020-02-01 19:25:37 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-05 23:17:23 +02:00
|
|
|
/**
|
|
|
|
|
* @param {jQuery} $tab
|
|
|
|
|
* @param {NoteContext} noteContext
|
|
|
|
|
*/
|
2023-04-11 21:41:55 +02:00
|
|
|
async updateTab($tab, noteContext) {
|
2020-05-12 12:45:32 +02:00
|
|
|
if (!$tab.length) {
|
2020-01-19 21:24:14 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
for (const clazz of Array.from($tab[0].classList)) {
|
|
|
|
|
// create copy to safely iterate over while removing classes
|
|
|
|
|
if (clazz !== "note-tab") {
|
2020-01-19 21:24:14 +01:00
|
|
|
$tab.removeClass(clazz);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-02 23:30:52 +02:00
|
|
|
let noteIcon = "";
|
|
|
|
|
|
2021-05-22 12:26:45 +02:00
|
|
|
if (noteContext) {
|
|
|
|
|
const hoistedNote = froca.getNoteFromCache(noteContext.hoistedNoteId);
|
2020-11-24 23:24:05 +01:00
|
|
|
|
2024-12-02 23:30:52 +02:00
|
|
|
if (hoistedNote) {
|
2025-01-09 18:07:02 +02:00
|
|
|
$tab.find(".note-tab-wrapper").css("--workspace-tab-background-color", hoistedNote.getWorkspaceTabBackgroundColor());
|
2024-12-02 23:30:52 +02:00
|
|
|
if (!this.showNoteIcons) {
|
|
|
|
|
noteIcon = hoistedNote.getWorkspaceIconClass();
|
|
|
|
|
}
|
2024-12-03 00:04:12 +02:00
|
|
|
} else {
|
2025-01-09 18:07:02 +02:00
|
|
|
$tab.find(".note-tab-wrapper").removeAttr("style");
|
2020-11-24 23:24:05 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
const { note } = noteContext;
|
2023-02-14 16:06:49 +01:00
|
|
|
|
2020-05-12 12:45:32 +02:00
|
|
|
if (!note) {
|
2025-01-09 18:07:02 +02:00
|
|
|
this.updateTitle($tab, t("tab_row.new_tab"));
|
2020-05-12 13:40:42 +02:00
|
|
|
return;
|
2025-01-09 18:07:02 +02:00
|
|
|
}
|
2020-05-12 12:45:32 +02:00
|
|
|
|
2023-04-11 21:41:55 +02:00
|
|
|
const title = await noteContext.getNavigationTitle();
|
2023-02-14 16:06:49 +01:00
|
|
|
this.updateTitle($tab, title);
|
2020-05-12 12:45:32 +02:00
|
|
|
|
2020-03-18 22:42:29 +01:00
|
|
|
$tab.addClass(note.getCssClass());
|
2020-01-19 21:24:14 +01:00
|
|
|
$tab.addClass(utils.getNoteTypeClass(note.type));
|
|
|
|
|
$tab.addClass(utils.getMimeTypeClass(note.mime));
|
2024-12-01 11:35:58 +02:00
|
|
|
|
2024-12-02 23:30:52 +02:00
|
|
|
if (this.showNoteIcons) {
|
|
|
|
|
noteIcon = note.getIcon();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (noteIcon) {
|
2025-01-09 18:07:02 +02:00
|
|
|
$tab.find(".note-tab-icon").removeClass().addClass("note-tab-icon").addClass(noteIcon);
|
2024-12-02 23:30:52 +02:00
|
|
|
}
|
2020-01-19 21:24:14 +01:00
|
|
|
}
|
2020-01-24 15:44:24 +01:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
async entitiesReloadedEvent({ loadResults }) {
|
2021-05-22 12:26:45 +02:00
|
|
|
for (const noteContext of appContext.tabManager.noteContexts) {
|
|
|
|
|
if (!noteContext.noteId) {
|
2021-02-07 20:55:49 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
if (
|
|
|
|
|
loadResults.isNoteReloaded(noteContext.noteId) ||
|
|
|
|
|
loadResults
|
|
|
|
|
.getAttributeRows()
|
|
|
|
|
.find((attr) => ["workspace", "workspaceIconClass", "workspaceTabBackgroundColor"].includes(attr.name) && attributeService.isAffecting(attr, noteContext.note))
|
2021-02-07 20:55:49 +01:00
|
|
|
) {
|
2021-05-22 12:26:45 +02:00
|
|
|
const $tab = this.getTabById(noteContext.ntxId);
|
2020-02-01 19:25:37 +01:00
|
|
|
|
2023-02-14 16:06:49 +01:00
|
|
|
this.updateTab($tab, noteContext);
|
2020-02-01 19:25:37 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-16 22:57:37 +02:00
|
|
|
frocaReloadedEvent() {
|
2021-05-22 12:26:45 +02:00
|
|
|
for (const noteContext of appContext.tabManager.noteContexts) {
|
|
|
|
|
const $tab = this.getTabById(noteContext.ntxId);
|
2020-02-01 22:29:32 +01:00
|
|
|
|
2023-02-14 16:06:49 +01:00
|
|
|
this.updateTab($tab, noteContext);
|
2020-02-01 22:29:32 +01:00
|
|
|
}
|
2020-01-24 15:44:24 +01:00
|
|
|
}
|
2021-02-07 21:27:09 +01:00
|
|
|
|
2025-01-09 18:07:02 +02:00
|
|
|
hoistedNoteChangedEvent({ ntxId }) {
|
2021-05-22 12:26:45 +02:00
|
|
|
const $tab = this.getTabById(ntxId);
|
2021-02-07 21:27:09 +01:00
|
|
|
|
|
|
|
|
if ($tab) {
|
2021-05-22 12:26:45 +02:00
|
|
|
const noteContext = appContext.tabManager.getNoteContextById(ntxId);
|
2021-02-07 21:27:09 +01:00
|
|
|
|
2023-02-14 16:06:49 +01:00
|
|
|
this.updateTab($tab, noteContext);
|
2021-02-07 21:27:09 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-12 12:45:32 +02:00
|
|
|
}
|