194 lines
6.2 KiB
JavaScript
194 lines
6.2 KiB
JavaScript
import Vue from 'vue'
|
|
import App from './App.vue'
|
|
import store from './store'
|
|
import i18n from './plugins/lang';
|
|
import router from './router'
|
|
import matrix from './services/matrix.service'
|
|
import navigation from './services/navigation.service'
|
|
import config from './services/config.service'
|
|
import analytics from './services/analytics.service'
|
|
import audioPlayer from './services/audio.service';
|
|
import 'roboto-fontface/css/roboto/roboto-fontface.css'
|
|
import 'material-design-icons-iconfont/dist/material-design-icons.css'
|
|
import VEmojiPicker from 'v-emoji-picker';
|
|
import VueResize from 'vue-resize';
|
|
import 'vue-resize/dist/vue-resize.css';
|
|
import VueClipboard from 'vue-clipboard2'
|
|
import VueSanitize from "vue-sanitize";
|
|
import createVuetify from './plugins/vuetify';
|
|
|
|
var defaultOptions = VueSanitize.defaults;
|
|
defaultOptions.disallowedTagsMode = "recursiveEscape";
|
|
defaultOptions.allowedTags = [];
|
|
Vue.use(VueSanitize, defaultOptions);
|
|
|
|
Vue.config.productionTip = false
|
|
|
|
Vue.use(VueResize);
|
|
Vue.use(VEmojiPicker);
|
|
Vue.use(matrix, { store: store, i18n: i18n });
|
|
|
|
const configLoadedPromise = new Promise((resolve, ignoredreject) => {
|
|
// eslint-disable-next-line
|
|
Vue.use(config, globalThis.window.location.origin, (config) => {
|
|
resolve(config);
|
|
}); // Use this before cleaninsights below, it depends on config!
|
|
});
|
|
Vue.use(analytics);
|
|
Vue.use(VueClipboard);
|
|
Vue.use(audioPlayer);
|
|
|
|
const vuetify = createVuetify(config);
|
|
|
|
// Add bubble functionality to custom events.
|
|
// From here: https://stackoverflow.com/questions/41993508/vuejs-bubbling-custom-events
|
|
Vue.use((Vue) => {
|
|
Vue.prototype.$bubble = function $bubble(eventName, ...args) {
|
|
// Emit the event on all parent components
|
|
let component = this;
|
|
let arg = args.at(0);
|
|
let stop = false;
|
|
if (arg) {
|
|
// Add a "stopPropagation" function so that we can do v-on:<eventname>.stop="..."
|
|
arg.stopPropagation = () => {
|
|
stop = true;
|
|
}
|
|
}
|
|
do {
|
|
component.$emit(eventName, ... args);
|
|
component = component.$parent;
|
|
} while (!stop && component);
|
|
};
|
|
});
|
|
|
|
// Register a global custom directive called `v-blur` that prevents focus
|
|
Vue.directive('blur', {
|
|
inserted: function (el) {
|
|
el.onfocus = (ev) => ev.target.blur()
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Handle long taps. Call with the timeout as argument (default 500ms) and the value
|
|
* can be either one function called on long tap or two functions, the
|
|
* first called on "short tap" and the other on "long tap".
|
|
*
|
|
* Like this: v-linkTap:500="[tapped,longTapped]"
|
|
*/
|
|
Vue.directive('longTap', {
|
|
bind: function (el, binding, ignoredvnode) {
|
|
el.longTapTimeout = parseInt(binding.arg || "500");
|
|
el.longTapCallbacks = binding.value;
|
|
for (var i = el.longTapCallbacks.length; i < 2; i++) {
|
|
el.longTapCallbacks.splice(0, 0, null);
|
|
}
|
|
|
|
const touchX = function (event) {
|
|
if (event.type.indexOf("mouse") !== -1) {
|
|
return event.clientX;
|
|
}
|
|
return event.touches[0].clientX;
|
|
};
|
|
const touchY = function (event) {
|
|
if (event.type.indexOf("mouse") !== -1) {
|
|
return event.clientY;
|
|
}
|
|
return event.touches[0].clientY;
|
|
};
|
|
|
|
/**
|
|
* Triggered when our "long tap" timer hits.
|
|
*/
|
|
const touchTimerElapsed = function () {
|
|
el.longTapHandled = true;
|
|
el.longTapCallbacks[1] && el.longTapCallbacks[1].call(el, el);
|
|
el.longTapTimer = null;
|
|
el.classList.remove("waiting-for-long-tap");
|
|
};
|
|
|
|
const touchStart = function (e) {
|
|
el.longTapHandled = false;
|
|
el.longTapStartX = touchX(e);
|
|
el.longTapStartY = touchY(e);
|
|
el.longTapTimer = setTimeout(touchTimerElapsed, el.longTapTimeout);
|
|
el.classList.add("waiting-for-long-tap");
|
|
e.preventDefault();
|
|
};
|
|
|
|
const touchCancel = function () {
|
|
el.longTapHandled = true;
|
|
el.longTapTimer && clearTimeout(el.longTapTimer);
|
|
el.longTapTimer = null;
|
|
el.classList.remove("waiting-for-long-tap");
|
|
};
|
|
|
|
const touchEnd = function () {
|
|
el.longTapTimer && clearTimeout(el.longTapTimer);
|
|
el.longTapTimer = null;
|
|
if (!el.longTapHandled) {
|
|
// Not canceled or long tapped. Just a single tap. Do we have a handler?
|
|
el.longTapCallbacks[0] && el.longTapCallbacks[0].call(el, el);
|
|
}
|
|
el.classList.remove("waiting-for-long-tap");
|
|
};
|
|
|
|
const touchMove = function (e) {
|
|
el.longTapCurrentX = touchX(e);
|
|
el.longTapCurrentY = touchY(e);
|
|
var tapTolerance = 4;
|
|
var touchMoved =
|
|
Math.abs(el.longTapStartX - el.longTapCurrentX) > tapTolerance ||
|
|
Math.abs(el.longTapStartY - el.longTapCurrentY) > tapTolerance;
|
|
if (touchMoved) {
|
|
touchCancel();
|
|
}
|
|
};
|
|
|
|
el.longTapTouchStart = touchStart;
|
|
el.longTapTouchEnd = touchEnd;
|
|
el.longTapTouchCancel = touchCancel;
|
|
el.longTapTouchMove = touchMove;
|
|
el.addEventListener("touchstart", touchStart);
|
|
el.addEventListener("touchend", touchEnd);
|
|
el.addEventListener("touchcancel", touchCancel);
|
|
el.addEventListener("touchmove", touchMove);
|
|
el.addEventListener("mousedown", touchStart);
|
|
el.addEventListener("mouseup", touchEnd);
|
|
el.addEventListener("mousemove", touchMove);
|
|
},
|
|
unbind: function (el) {
|
|
el.longTapTimer && clearTimeout(el.longTapTimer);
|
|
el.removeEventListener("touchstart", el.longTapTouchStart);
|
|
el.removeEventListener("touchend", el.longTapTouchEnd);
|
|
el.removeEventListener("touchcancel", el.longTapTouchCancel);
|
|
el.removeEventListener("touchmove", el.longTapTouchMove);
|
|
el.removeEventListener("mousedown", el.longTapTouchStart);
|
|
el.removeEventListener("mouseup", el.longTapTouchEnd);
|
|
el.removeEventListener("mousemove", el.longTapTouchMove);
|
|
},
|
|
});
|
|
|
|
Vue.use(navigation, router);
|
|
|
|
const vueInstance = new Vue({
|
|
vuetify,
|
|
store,
|
|
i18n,
|
|
router,
|
|
matrix,
|
|
config,
|
|
analytics,
|
|
audioPlayer,
|
|
render: h => h(App),
|
|
});
|
|
if (vueInstance.$config.accentColor) {
|
|
vueInstance.$vuetify.theme.themes.light.primary = vueInstance.$config.accentColor;
|
|
}
|
|
vueInstance.$audioPlayer.$root = vueInstance; // Make sure a $root is available here
|
|
configLoadedPromise.then((config) => {
|
|
if (config.accentColor) {
|
|
vueInstance.$vuetify.theme.themes.light.primary = config.accentColor;
|
|
}
|
|
vueInstance.$mount('#app');
|
|
});
|
|
|