splitup common.js
This commit is contained in:
34
resources/js/bootstrap.js
vendored
34
resources/js/bootstrap.js
vendored
@@ -1,34 +0,0 @@
|
||||
import _ from "lodash";
|
||||
window._ = _;
|
||||
|
||||
/**
|
||||
* We'll load the axios HTTP library which allows us to easily issue requests
|
||||
* to our Laravel back-end. This library automatically handles sending the
|
||||
* CSRF token as a header based on the value of the "XSRF" token cookie.
|
||||
*/
|
||||
|
||||
// import axios from 'axios';
|
||||
// window.axios = axios;
|
||||
|
||||
// window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
|
||||
|
||||
/**
|
||||
* Echo exposes an expressive API for subscribing to channels and listening
|
||||
* for events that are broadcast by Laravel. Echo and event broadcasting
|
||||
* allows your team to easily build robust real-time web applications.
|
||||
*/
|
||||
|
||||
// import Echo from 'laravel-echo';
|
||||
|
||||
// import Pusher from 'pusher-js';
|
||||
// window.Pusher = Pusher;
|
||||
|
||||
// window.Echo = new Echo({
|
||||
// broadcaster: 'pusher',
|
||||
// key: import.meta.env.VITE_PUSHER_APP_KEY,
|
||||
// wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
|
||||
// wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
|
||||
// wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
|
||||
// forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
|
||||
// enabledTransports: ['ws', 'wss'],
|
||||
// });
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<script setup lang="ts">
|
||||
import Trix from "trix";
|
||||
import { ref, watch, computed, onUnmounted } from "vue";
|
||||
import { arrayIncludesMatchBasic } from "../helpers/common";
|
||||
import { arrayHasBasicMatch } from "../helpers/array";
|
||||
|
||||
import DialogMedia from "./dialogs/SMDialogMedia.vue";
|
||||
import { openDialog } from "vue3-promise-dialog";
|
||||
@@ -154,7 +154,7 @@ const emitEditorState = (value) => {
|
||||
|
||||
const emitFileAccept = (event) => {
|
||||
if (props.mimeTypes) {
|
||||
if (!arrayIncludesMatchBasic(props.mimeTypes, event.file.type)) {
|
||||
if (!arrayHasBasicMatch(props.mimeTypes, event.file.type)) {
|
||||
window.alert("That file type is not supported");
|
||||
event.preventDefault();
|
||||
return;
|
||||
|
||||
@@ -20,7 +20,7 @@ const parsedContent = computed(() => {
|
||||
`<a ([^>]*?)href="${import.meta.env.APP_URL}(.*?>.*?)</a>`,
|
||||
"ig"
|
||||
);
|
||||
html = props.html.replaceAll(regex, '<router-link $1to="$2</router-link>');
|
||||
html = props.html.replace(regex, '<router-link $1to="$2</router-link>');
|
||||
|
||||
return {
|
||||
template: `<div class="content">${html}</div>`,
|
||||
|
||||
@@ -39,12 +39,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, computed, ref } from "vue";
|
||||
import {
|
||||
excerpt,
|
||||
isUUID,
|
||||
replaceHtmlEntites,
|
||||
stripHtmlTags,
|
||||
} from "../helpers/common";
|
||||
import { isUUID } from "../helpers/types";
|
||||
import { excerpt, replaceHtmlEntites, stripHtmlTags } from "../helpers/string";
|
||||
import { format } from "date-fns";
|
||||
import { api } from "../helpers/api";
|
||||
import { imageLoad } from "../helpers/image";
|
||||
|
||||
@@ -80,7 +80,6 @@ import SMFormFooter from "../SMFormFooter.vue";
|
||||
import SMDialog from "../SMDialog.vue";
|
||||
import SMMessage from "../SMMessage.vue";
|
||||
import SMModal from "../SMModal.vue";
|
||||
import { toParamString } from "../../helpers/common";
|
||||
import { api } from "../../helpers/api";
|
||||
|
||||
const uploader = ref(null);
|
||||
@@ -134,10 +133,13 @@ const handleLoad = async () => {
|
||||
params.limit = perPage.value;
|
||||
// params.fields = "url";
|
||||
|
||||
let res = await api.get(`/media${toParamString(params)}`);
|
||||
let res = await api.get({
|
||||
url: "/media",
|
||||
params: params,
|
||||
});
|
||||
|
||||
totalItems.value = res.json.total;
|
||||
mediaItems.value = res.json.media;
|
||||
totalItems.value = res.data.total;
|
||||
mediaItems.value = res.data.media;
|
||||
} catch (error) {
|
||||
if (error.status == 404) {
|
||||
formMessage.type = "primary";
|
||||
@@ -145,7 +147,7 @@ const handleLoad = async () => {
|
||||
formMessage.message = "No media items found";
|
||||
} else {
|
||||
formMessage.message =
|
||||
error?.json?.message || "An unexpected error occurred";
|
||||
error?.data?.message || "An unexpected error occurred";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
24
resources/js/helpers/array.ts
Normal file
24
resources/js/helpers/array.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Test if array has a match using basic search (* means anything)
|
||||
*
|
||||
* @param {Array<string>} arr The array to search.
|
||||
* @param {string} str The string to find.
|
||||
* @returns {boolean} if the array has the string.
|
||||
*/
|
||||
export const arrayHasBasicMatch = (
|
||||
arr: Array<string>,
|
||||
str: string
|
||||
): boolean => {
|
||||
let matches = false;
|
||||
|
||||
arr.every((elem) => {
|
||||
elem = elem.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
||||
const regex = new RegExp("^" + elem.replace("*", ".*?") + "$", "i");
|
||||
if (str.match(regex)) {
|
||||
matches = true;
|
||||
}
|
||||
return !matches;
|
||||
});
|
||||
|
||||
return matches;
|
||||
};
|
||||
@@ -1,318 +0,0 @@
|
||||
const transitionEndEventName = () => {
|
||||
var i,
|
||||
undefined,
|
||||
el = document.createElement("div"),
|
||||
transitions = {
|
||||
transition: "transitionend",
|
||||
OTransition: "otransitionend",
|
||||
MozTransition: "transitionend",
|
||||
WebkitTransition: "webkitTransitionEnd",
|
||||
};
|
||||
|
||||
for (i in transitions) {
|
||||
if (transitions.hasOwnProperty(i) && el.style[i] !== undefined) {
|
||||
return transitions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
const waitForElementRender = (elem) => {
|
||||
return new Promise((resolve) => {
|
||||
if (document.contains(elem.value)) {
|
||||
return resolve(elem.value);
|
||||
}
|
||||
|
||||
const MutationObserver =
|
||||
window.MutationObserver ||
|
||||
window.WebKitMutationObserver ||
|
||||
window.MozMutationObserver;
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
if (document.contains(elem.value)) {
|
||||
resolve(elem.value);
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const transitionEnter = (elem, transition) => {
|
||||
waitForElementRender(elem).then((e) => {
|
||||
window.setTimeout(() => {
|
||||
e.classList.replace(
|
||||
transition + "-enter-from",
|
||||
transition + "-enter-active"
|
||||
);
|
||||
const transitionName = transitionEndEventName();
|
||||
e.addEventListener(
|
||||
transitionName,
|
||||
() => {
|
||||
e.classList.replace(
|
||||
transition + "-enter-active",
|
||||
transition + "-enter-to"
|
||||
);
|
||||
},
|
||||
false
|
||||
);
|
||||
}, 1);
|
||||
});
|
||||
};
|
||||
|
||||
const transitionLeave = (elem, transition, callback = null) => {
|
||||
elem.value.classList.remove(transition + "-enter-to");
|
||||
elem.value.classList.add(transition + "-leave-from");
|
||||
window.setTimeout(() => {
|
||||
elem.value.classList.replace(
|
||||
transition + "-leave-from",
|
||||
transition + "-leave-active"
|
||||
);
|
||||
const transitionName = transitionEndEventName();
|
||||
elem.value.addEventListener(
|
||||
transitionName,
|
||||
() => {
|
||||
elem.value.classList.replace(
|
||||
transition + "-leave-active",
|
||||
transition + "-leave-to"
|
||||
);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
}, 1);
|
||||
};
|
||||
|
||||
export const monthString = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
|
||||
export const fullMonthString = [
|
||||
"January",
|
||||
"February",
|
||||
"March",
|
||||
"April",
|
||||
"May",
|
||||
"June",
|
||||
"July",
|
||||
"August",
|
||||
"September",
|
||||
"October",
|
||||
"November",
|
||||
"December",
|
||||
];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
*/
|
||||
export function isBool(target) {
|
||||
return typeof target === "boolean";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
*/
|
||||
export function isNumber(target) {
|
||||
return typeof target === "number";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
*/
|
||||
export function isObject(target) {
|
||||
return typeof target === "object" && target !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
*/
|
||||
export function isString(target) {
|
||||
return typeof target === "string" && target !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param target
|
||||
* @param def
|
||||
*/
|
||||
export function parseErrorType(
|
||||
target,
|
||||
def = "An unknown error occurred. Please try again later."
|
||||
) {
|
||||
if (target.response?.message) {
|
||||
return target.response.message;
|
||||
} else if (target instanceof Error) {
|
||||
target.message;
|
||||
} else if (isString(err)) {
|
||||
return target;
|
||||
}
|
||||
|
||||
return def;
|
||||
}
|
||||
|
||||
export const buildUrlQuery = (url, query) => {
|
||||
let s = "";
|
||||
|
||||
if (Object.keys(query).length > 0) {
|
||||
s = "?";
|
||||
}
|
||||
|
||||
s += Object.keys(query)
|
||||
.map((key) => key + "=" + query[key])
|
||||
.join("&");
|
||||
|
||||
return url + s;
|
||||
};
|
||||
|
||||
export const toParamString = (obj, q = true) => {
|
||||
let s = "";
|
||||
|
||||
if (q && Object.keys(obj).length > 0) {
|
||||
s = "?";
|
||||
}
|
||||
|
||||
s += Object.keys(obj)
|
||||
.map((key) => key + "=" + obj[key])
|
||||
.join("&");
|
||||
return s;
|
||||
};
|
||||
|
||||
export const getLocale = () => {
|
||||
return (
|
||||
navigator.userLanguage ||
|
||||
(navigator.languages &&
|
||||
navigator.languages.length &&
|
||||
navigator.languages[0]) ||
|
||||
navigator.language ||
|
||||
navigator.browserLanguage ||
|
||||
navigator.systemLanguage ||
|
||||
"en"
|
||||
);
|
||||
};
|
||||
|
||||
export const debounce = (fn, delay) => {
|
||||
var timeoutID = null;
|
||||
return function () {
|
||||
clearTimeout(timeoutID);
|
||||
var args = arguments;
|
||||
var that = this;
|
||||
timeoutID = setTimeout(function () {
|
||||
fn.apply(that, args);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
|
||||
export const bytesReadable = (bytes) => {
|
||||
if (isNaN(bytes)) {
|
||||
return "0 Bytes";
|
||||
}
|
||||
|
||||
if (Math.abs(bytes) < 1024) {
|
||||
return bytes + " Bytes";
|
||||
}
|
||||
|
||||
const units = ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
let u = -1;
|
||||
const r = 10 ** 1;
|
||||
|
||||
do {
|
||||
bytes /= 1000;
|
||||
++u;
|
||||
} while (
|
||||
Math.round(Math.abs(bytes) * r) / r >= 1000 &&
|
||||
u < units.length - 1
|
||||
);
|
||||
|
||||
return bytes.toFixed(1) + " " + units[u];
|
||||
};
|
||||
|
||||
export const arrayIncludesMatchBasic = (arr, str) => {
|
||||
let matches = false;
|
||||
|
||||
arr.every((elem) => {
|
||||
elem = elem.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
||||
let regex = new RegExp("^" + elem.replace("*", ".*?") + "$", "i");
|
||||
if (str.match(regex)) {
|
||||
matches = true;
|
||||
}
|
||||
return !matches;
|
||||
});
|
||||
|
||||
return matches;
|
||||
};
|
||||
|
||||
export const excerpt = (txt, maxLen = 150, strip = true) => {
|
||||
if (strip) {
|
||||
txt = stripHtmlTags(replaceHtmlEntites(txt));
|
||||
}
|
||||
|
||||
let txtPieces = txt.split(" ");
|
||||
let excerptPieces = [];
|
||||
let curLen = 0;
|
||||
|
||||
txtPieces.every((itm) => {
|
||||
if (curLen + itm.length >= maxLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
excerptPieces.push(itm);
|
||||
curLen += itm.length + 1;
|
||||
return true;
|
||||
});
|
||||
|
||||
return excerptPieces.join(" ") + (curLen < txt.length ? "..." : "");
|
||||
};
|
||||
|
||||
export const stripHtmlTags = (txt) => {
|
||||
txt = txt.replace(/<(p|br)([ /]*?>|[ /]+.*?>)/g, " ");
|
||||
return txt.replace(/<[a-zA-Z/][^>]+(>|$)/g, "");
|
||||
};
|
||||
|
||||
export const replaceHtmlEntites = (txt) => {
|
||||
var translate_re = /&(nbsp|amp|quot|lt|gt);/g;
|
||||
var translate = {
|
||||
nbsp: " ",
|
||||
amp: "&",
|
||||
quot: '"',
|
||||
lt: "<",
|
||||
gt: ">",
|
||||
};
|
||||
|
||||
return txt.replace(translate_re, function (match, entity) {
|
||||
return translate[entity];
|
||||
});
|
||||
};
|
||||
|
||||
export const isUUID = (uuid) => {
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
||||
uuid
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
transitionEndEventName,
|
||||
waitForElementRender,
|
||||
transitionEnter,
|
||||
transitionLeave,
|
||||
};
|
||||
27
resources/js/helpers/debounce.ts
Normal file
27
resources/js/helpers/debounce.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
type DebounceCallback = () => void;
|
||||
type DebounceResult = (...args: unknown[]) => void;
|
||||
|
||||
/**
|
||||
* Call a function after a delay once.
|
||||
*
|
||||
* @param {Function} fn The function to call.
|
||||
* @param {number} delay The delay before calling function.
|
||||
* @returns {void}
|
||||
*/
|
||||
export const debounce = (
|
||||
fn: DebounceCallback,
|
||||
delay: number
|
||||
): DebounceResult => {
|
||||
let timeoutID: NodeJS.Timeout | null = null;
|
||||
return (...args) => {
|
||||
if (timeoutID != null) {
|
||||
clearTimeout(timeoutID);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const that = this;
|
||||
timeoutID = setTimeout(function () {
|
||||
fn.apply(that, args);
|
||||
}, delay);
|
||||
};
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
export const toTitleCase = (str) => {
|
||||
return str.replace(/\w\S*/g, function (txt) {
|
||||
return (
|
||||
txt.charAt(0).toUpperCase() +
|
||||
txt.substr(1).replaceAll("_", " ").toLowerCase()
|
||||
);
|
||||
});
|
||||
};
|
||||
81
resources/js/helpers/string.ts
Normal file
81
resources/js/helpers/string.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Transforms a string to title case.
|
||||
*
|
||||
* @param {string} str The string to transform.
|
||||
* @returns {string} A string transformed to title case.
|
||||
*/
|
||||
export const toTitleCase = (str: string): string => {
|
||||
return str.replace(/\w\S*/g, function (txt) {
|
||||
return (
|
||||
txt.charAt(0).toUpperCase() +
|
||||
txt.substring(1).replace(/_/g, " ").toLowerCase()
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a string to a excerpt.
|
||||
*
|
||||
* @param {string} txt The text to convert.
|
||||
* @param {number} maxLen (optional) The maximum length of the excerpt.
|
||||
* @param {boolean} strip (optional) Strip HTML tags from the text.
|
||||
* @param stripHtml
|
||||
* @returns {string} The excerpt.
|
||||
*/
|
||||
export const excerpt = (
|
||||
txt: string,
|
||||
maxLen: number = 150,
|
||||
stripHtml: boolean = true
|
||||
): string => {
|
||||
if (stripHtml) {
|
||||
txt = stripHtmlTags(replaceHtmlEntites(txt));
|
||||
}
|
||||
|
||||
const txtPieces = txt.split(" ");
|
||||
const excerptPieces: string[] = [];
|
||||
let curLen = 0;
|
||||
|
||||
txtPieces.every((itm) => {
|
||||
if (curLen + itm.length >= maxLen) {
|
||||
return false;
|
||||
}
|
||||
|
||||
excerptPieces.push(itm);
|
||||
curLen += itm.length + 1;
|
||||
return true;
|
||||
});
|
||||
|
||||
return excerptPieces.join(" ") + (curLen < txt.length ? "..." : "");
|
||||
};
|
||||
|
||||
/**
|
||||
* String HTML tags from text.
|
||||
*
|
||||
* @param {string} txt The text to strip tags.
|
||||
* @returns {string} The stripped text.
|
||||
*/
|
||||
export const stripHtmlTags = (txt: string): string => {
|
||||
txt = txt.replace(/<(p|br)([ /]*?>|[ /]+.*?>)/g, " ");
|
||||
return txt.replace(/<[a-zA-Z/][^>]+(>|$)/g, "");
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace HTML entities with real characters.
|
||||
*
|
||||
* @param {string} txt The text to transform.
|
||||
* @returns {string} Transformed text
|
||||
*/
|
||||
export const replaceHtmlEntites = (txt: string): string => {
|
||||
const translate_re = /&(nbsp|amp|quot|lt|gt);/g;
|
||||
const translate = {
|
||||
nbsp: " ",
|
||||
amp: "&",
|
||||
quot: '"',
|
||||
lt: "<",
|
||||
gt: ">",
|
||||
};
|
||||
|
||||
return txt.replace(translate_re, function (match, entity) {
|
||||
return translate[entity];
|
||||
});
|
||||
};
|
||||
127
resources/js/helpers/transition.ts
Normal file
127
resources/js/helpers/transition.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import { Ref } from "vue";
|
||||
|
||||
/**
|
||||
* Return the browser transiton end name.
|
||||
*
|
||||
* @returns {string} The browser transition end name.
|
||||
*/
|
||||
const transitionEndEventName = (): string => {
|
||||
const el = document.createElement("div"),
|
||||
transitions: Record<string, string> = {
|
||||
transition: "transitionend",
|
||||
OTransition: "otransitionend",
|
||||
MozTransition: "transitionend",
|
||||
WebkitTransition: "webkitTransitionEnd",
|
||||
};
|
||||
|
||||
for (const i in transitions) {
|
||||
if (
|
||||
Object.prototype.hasOwnProperty.call(transitions, i) &&
|
||||
el.style[i] !== undefined
|
||||
) {
|
||||
return transitions[i];
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for the element to render as Promise
|
||||
*
|
||||
* @param elem The
|
||||
* @returns
|
||||
*/
|
||||
const waitForElementRender = (elem: Ref): Promise<HTMLElement> => {
|
||||
return new Promise((resolve) => {
|
||||
if (document.contains(elem.value)) {
|
||||
return resolve(elem.value as HTMLElement);
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
const MutationObserver =
|
||||
window.MutationObserver ||
|
||||
(window as any).WebKitMutationObserver ||
|
||||
(window as any).MozMutationObserver;
|
||||
/* eslint-enable @typescript-eslint/no-explicit-any */
|
||||
const observer = new MutationObserver(() => {
|
||||
if (document.contains(elem.value)) {
|
||||
resolve(elem.value);
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Run the enter transition on a element.
|
||||
*
|
||||
* @param {Ref} elem The element to run the enter transition.
|
||||
* @param {string} transition The transition name.
|
||||
* @returns {void}
|
||||
*/
|
||||
export const transitionEnter = (elem: Ref, transition: string): void => {
|
||||
waitForElementRender(elem).then((e: HTMLElement) => {
|
||||
window.setTimeout(() => {
|
||||
e.classList.replace(
|
||||
transition + "-enter-from",
|
||||
transition + "-enter-active"
|
||||
);
|
||||
const transitionName = transitionEndEventName();
|
||||
e.addEventListener(
|
||||
transitionName,
|
||||
() => {
|
||||
e.classList.replace(
|
||||
transition + "-enter-active",
|
||||
transition + "-enter-to"
|
||||
);
|
||||
},
|
||||
false
|
||||
);
|
||||
}, 1);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Run the exit transition on a element then call a callback.
|
||||
*
|
||||
* @param {Ref} elem The element to run the enter transition.
|
||||
* @param {string} transition The transition name.
|
||||
* @param {TransitionLeaveCallback|null} callback The callback to run after the transition finishes.
|
||||
* @returns {void}
|
||||
*/
|
||||
type TransitionLeaveCallback = () => void;
|
||||
|
||||
export const transitionLeave = (
|
||||
elem: Ref,
|
||||
transition: string,
|
||||
callback: TransitionLeaveCallback | null = null
|
||||
): void => {
|
||||
elem.value.classList.remove(transition + "-enter-to");
|
||||
elem.value.classList.add(transition + "-leave-from");
|
||||
window.setTimeout(() => {
|
||||
elem.value.classList.replace(
|
||||
transition + "-leave-from",
|
||||
transition + "-leave-active"
|
||||
);
|
||||
const transitionName = transitionEndEventName();
|
||||
elem.value.addEventListener(
|
||||
transitionName,
|
||||
() => {
|
||||
elem.value.classList.replace(
|
||||
transition + "-leave-active",
|
||||
transition + "-leave-to"
|
||||
);
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
}, 1);
|
||||
};
|
||||
81
resources/js/helpers/types.ts
Normal file
81
resources/js/helpers/types.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Test if target is a boolean
|
||||
*
|
||||
* @param {unknown} target The varible to test
|
||||
* @returns {boolean} If the varible is a boolean type
|
||||
*/
|
||||
export function isBool(target: unknown): boolean {
|
||||
return typeof target === "boolean";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if target is a number
|
||||
*
|
||||
* @param {unknown} target The varible to test
|
||||
* @returns {boolean} If the varible is a number type
|
||||
*/
|
||||
export function isNumber(target: unknown): boolean {
|
||||
return typeof target === "number";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if target is an object
|
||||
*
|
||||
* @param {unknown} target The varible to test
|
||||
* @returns {boolean} If the varible is a object type
|
||||
*/
|
||||
export function isObject(target: unknown): boolean {
|
||||
return typeof target === "object" && target !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if target is a string
|
||||
*
|
||||
* @param {unknown} target The varible to test
|
||||
* @returns {boolean} If the varible is a string type
|
||||
*/
|
||||
export function isString(target: unknown): boolean {
|
||||
return typeof target === "string" && target !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if target is a UUID
|
||||
*
|
||||
* @param {string} uuid The variable to test
|
||||
* @returns {boolean} If the varible is a UUID
|
||||
*/
|
||||
export const isUUID = (uuid: string): boolean => {
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
|
||||
uuid
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert bytes to a human readable string.
|
||||
*
|
||||
* @param {number} bytes The bytes to convert.
|
||||
* @returns {string} The bytes in human readable string.
|
||||
*/
|
||||
export const bytesReadable = (bytes: number): string => {
|
||||
if (isNaN(bytes)) {
|
||||
return "0 Bytes";
|
||||
}
|
||||
|
||||
if (Math.abs(bytes) < 1024) {
|
||||
return bytes + " Bytes";
|
||||
}
|
||||
|
||||
const units = ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
let u = -1;
|
||||
const r = 10 ** 1;
|
||||
|
||||
do {
|
||||
bytes /= 1000;
|
||||
++u;
|
||||
} while (
|
||||
Math.round(Math.abs(bytes) * r) / r >= 1000 &&
|
||||
u < units.length - 1
|
||||
);
|
||||
|
||||
return bytes.toFixed(1) + " " + units[u];
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SMDate } from "./datetime";
|
||||
import { bytesReadable } from "../helpers/common";
|
||||
import { bytesReadable } from "../helpers/types";
|
||||
|
||||
export interface ValidationObject {
|
||||
validate: (value: string) => ValidationResult;
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onBeforeMount } from "vue";
|
||||
import { transitionEnter, transitionLeave } from "../helpers/common";
|
||||
import { ref } from "vue";
|
||||
import { transitionEnter, transitionLeave } from "../helpers/transition";
|
||||
|
||||
const root = ref(null);
|
||||
const classes = ref(["mdialog-mask", "fade-enter-from"]);
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from "vue";
|
||||
import { excerpt } from "../helpers/common";
|
||||
import { excerpt } from "../helpers/string";
|
||||
import { SMDate } from "../helpers/datetime";
|
||||
import SMInput from "../components/SMInput.vue";
|
||||
import SMButton from "../components/SMButton.vue";
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { fullMonthString } from "../helpers/common";
|
||||
import { SMDate } from "../helpers/datetime";
|
||||
import { useApplicationStore } from "../store/ApplicationStore";
|
||||
import { api } from "../helpers/api";
|
||||
@@ -92,14 +91,7 @@ const loadData = async () => {
|
||||
};
|
||||
|
||||
const formattedPublishAt = (dateStr) => {
|
||||
const date = new Date(Date.parse(dateStr));
|
||||
return (
|
||||
fullMonthString[date.getMonth()] +
|
||||
" " +
|
||||
date.getDate() +
|
||||
", " +
|
||||
date.getFullYear()
|
||||
);
|
||||
return new SMDate(dateStr, { format: "yMd" }).format("MMMM d, yyyy");
|
||||
};
|
||||
|
||||
const formattedContent = computed(() => {
|
||||
@@ -109,7 +101,7 @@ const formattedContent = computed(() => {
|
||||
`<a ([^>]*?)href="${import.meta.env.APP_URL}(.*?>.*?)</a>`,
|
||||
"ig"
|
||||
);
|
||||
html = html.replaceAll(regex, '<router-link $1to="$2</router-link>');
|
||||
html = html.replace(regex, '<router-link $1to="$2</router-link>');
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -88,7 +88,7 @@ import {
|
||||
Required,
|
||||
} from "../helpers/validate";
|
||||
|
||||
import { debounce } from "../helpers/common";
|
||||
import { debounce } from "../helpers/debounce";
|
||||
import { useReCaptcha } from "vue-recaptcha-v3";
|
||||
|
||||
const { executeRecaptcha, recaptchaLoaded } = useReCaptcha();
|
||||
|
||||
@@ -52,13 +52,13 @@
|
||||
import { ref, watch, reactive } from "vue";
|
||||
import EasyDataTable from "vue3-easy-data-table";
|
||||
import { api } from "../../helpers/api";
|
||||
import { relativeDate, timestampUtcToLocal } from "../../helpers/datetime";
|
||||
import { SMDate } from "../../helpers/datetime";
|
||||
import { useRouter } from "vue-router";
|
||||
import SMDialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
|
||||
import { openDialog } from "vue3-promise-dialog";
|
||||
import SMToolbar from "../../components/SMToolbar.vue";
|
||||
import SMButton from "../../components/SMButton.vue";
|
||||
import { debounce } from "../../helpers/common";
|
||||
import { debounce } from "../../helpers/debounce";
|
||||
import SMHeading from "../../components/SMHeading.vue";
|
||||
import SMMessage from "../../components/SMMessage.vue";
|
||||
import SMLoadingIcon from "../../components/SMLoadingIcon.vue";
|
||||
@@ -128,13 +128,22 @@ const loadFromServer = async () => {
|
||||
|
||||
items.value.forEach((row) => {
|
||||
if (row.start_at !== "undefined") {
|
||||
row.start_at = relativeDate(timestampUtcToLocal(row.start_at));
|
||||
row.start_at = new SMDate(row.start_at, {
|
||||
format: "ymd",
|
||||
utc: true,
|
||||
}).relative();
|
||||
}
|
||||
if (row.created_at !== "undefined") {
|
||||
row.created_at = relativeDate(row.created_at);
|
||||
row.created_at = new SMDate(row.creative_at, {
|
||||
format: "ymd",
|
||||
utc: true,
|
||||
}).relative();
|
||||
}
|
||||
if (row.updated_at !== "undefined") {
|
||||
row.updated_at = relativeDate(row.updated_at);
|
||||
row.updated_at = new SMDate(row.updated_at, {
|
||||
format: "ymd",
|
||||
utc: true,
|
||||
}).relative();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ import { api } from "../../helpers/api";
|
||||
import { FormObject, FormControl } from "../../helpers/form";
|
||||
import { And, Required, FileSize } from "../../helpers/validate";
|
||||
import { useRoute } from "vue-router";
|
||||
import { bytesReadable } from "../../helpers/common";
|
||||
import { bytesReadable } from "../../helpers/types";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@@ -61,7 +61,8 @@ import DialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
|
||||
import { openDialog } from "vue3-promise-dialog";
|
||||
import SMToolbar from "../../components/SMToolbar.vue";
|
||||
import SMButton from "../../components/SMButton.vue";
|
||||
import { debounce, parseErrorType, bytesReadable } from "../../helpers/common";
|
||||
import { debounce } from "../../helpers/debounce";
|
||||
import { bytesReadable } from "../../helpers/types";
|
||||
import SMMessage from "../../components/SMMessage.vue";
|
||||
import SMFileLink from "../../components/SMFileLink.vue";
|
||||
import { useUserStore } from "../../store/UserStore";
|
||||
@@ -161,7 +162,7 @@ const loadFromServer = async () => {
|
||||
|
||||
serverItemsLength.value = res.data.total;
|
||||
} catch (err) {
|
||||
formMessage.message = parseErrorType(err);
|
||||
// formMessage.message = parseErrorTyp(err);
|
||||
}
|
||||
|
||||
formLoading.value = false;
|
||||
|
||||
@@ -51,14 +51,14 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, reactive } from "vue";
|
||||
import EasyDataTable from "vue3-easy-data-table";
|
||||
import { relativeDate } from "../../helpers/datetime";
|
||||
import { SMDate } from "../../helpers/datetime";
|
||||
import { useRouter } from "vue-router";
|
||||
import SMDialogConfirm from "../../components/dialogs/SMDialogConfirm.vue";
|
||||
import { openDialog } from "vue3-promise-dialog";
|
||||
import { api } from "../../helpers/api";
|
||||
import SMToolbar from "../../components/SMToolbar.vue";
|
||||
import SMButton from "../../components/SMButton.vue";
|
||||
import { debounce } from "../../helpers/common";
|
||||
import { debounce } from "../../helpers/debounce";
|
||||
import SMHeading from "../../components/SMHeading.vue";
|
||||
import SMMessage from "../../components/SMMessage.vue";
|
||||
import SMLoadingIcon from "../../components/SMLoadingIcon.vue";
|
||||
@@ -124,18 +124,15 @@ const loadFromServer = async () => {
|
||||
|
||||
items.value.forEach((row) => {
|
||||
if (row.created_at !== "undefined") {
|
||||
row.created_at = relativeDate(
|
||||
timestampUtcToLocal(row.created_at)
|
||||
row.created_at = new SMDate(row.created_at, {format: 'yMd', utc: true}).relative();
|
||||
);
|
||||
}
|
||||
if (row.updated_at !== "undefined") {
|
||||
row.updated_at = relativeDate(
|
||||
timestampUtcToLocal(row.updated_at)
|
||||
row.updated_at = new SMDate(row.updated_at, {format: 'yMd', utc: true}).relative();
|
||||
);
|
||||
}
|
||||
if (row.publish_at !== "undefined") {
|
||||
row.publish_at = relativeDate(
|
||||
timestampUtcToLocal(row.publish_at)
|
||||
row.publish_at = new SMDate(row.publish_at, {format: 'yMd', utc: true}).relative();
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user