style: Apply Prettier formatting with 4-space indentation
Applied consistent code formatting across the project using Prettier, now configured to use 4-space indentation instead of tabs.
This commit is contained in:
@@ -1,170 +1,170 @@
|
||||
let _cmCache: {
|
||||
EditorView?: any;
|
||||
EditorState?: any;
|
||||
basicSetup?: any;
|
||||
markdown?: any;
|
||||
markdownLanguage?: any;
|
||||
keymap?: any;
|
||||
defaultKeymap?: any;
|
||||
history?: any;
|
||||
historyKeymap?: any;
|
||||
lineNumbers?: any;
|
||||
highlightSpecialChars?: any;
|
||||
drawSelection?: any;
|
||||
dropCursor?: any;
|
||||
rectangularSelection?: any;
|
||||
crosshairCursor?: any;
|
||||
highlightActiveLine?: any;
|
||||
highlightActiveLineGutter?: any;
|
||||
indentWithTab?: any;
|
||||
indentUnit?: any;
|
||||
autocompletion?: any;
|
||||
completionKeymap?: any;
|
||||
closeBrackets?: any;
|
||||
closeBracketsKeymap?: any;
|
||||
searchKeymap?: any;
|
||||
highlightSelectionMatches?: any;
|
||||
lintKeymap?: any;
|
||||
EditorState_allowMultipleSelections?: any;
|
||||
EditorView_lineWrapping?: any;
|
||||
EditorView_editable?: any;
|
||||
EditorView_contentAttributes?: any;
|
||||
bracketMatching?: any;
|
||||
foldGutter?: any;
|
||||
foldKeymap?: any;
|
||||
indentOnInput?: any;
|
||||
languages?: any;
|
||||
oneDark?: any;
|
||||
placeholderExt?: any;
|
||||
EditorView?: any;
|
||||
EditorState?: any;
|
||||
basicSetup?: any;
|
||||
markdown?: any;
|
||||
markdownLanguage?: any;
|
||||
keymap?: any;
|
||||
defaultKeymap?: any;
|
||||
history?: any;
|
||||
historyKeymap?: any;
|
||||
lineNumbers?: any;
|
||||
highlightSpecialChars?: any;
|
||||
drawSelection?: any;
|
||||
dropCursor?: any;
|
||||
rectangularSelection?: any;
|
||||
crosshairCursor?: any;
|
||||
highlightActiveLine?: any;
|
||||
highlightActiveLineGutter?: any;
|
||||
indentWithTab?: any;
|
||||
indentUnit?: any;
|
||||
autocompletion?: any;
|
||||
completionKeymap?: any;
|
||||
closeBrackets?: any;
|
||||
closeBracketsKeymap?: any;
|
||||
searchKeymap?: any;
|
||||
highlightSelectionMatches?: any;
|
||||
lintKeymap?: any;
|
||||
EditorState_allowMultipleSelections?: any;
|
||||
EditorView_lineWrapping?: any;
|
||||
EditorView_editable?: any;
|
||||
EditorView_contentAttributes?: any;
|
||||
bracketMatching?: any;
|
||||
foldGutter?: any;
|
||||
foldKeymap?: any;
|
||||
indentOnInput?: any;
|
||||
languages?: any;
|
||||
oneDark?: any;
|
||||
placeholderExt?: any;
|
||||
} | null = null;
|
||||
|
||||
// ...existing code...
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
type CMCache = {
|
||||
EditorView: any;
|
||||
EditorState: any;
|
||||
basicSetup?: any;
|
||||
markdown?: any;
|
||||
markdownLanguage?: any;
|
||||
keymap?: any;
|
||||
defaultKeymap?: any;
|
||||
history?: any;
|
||||
historyKeymap?: any;
|
||||
lineNumbers?: any;
|
||||
highlightSpecialChars?: any;
|
||||
drawSelection?: any;
|
||||
dropCursor?: any;
|
||||
rectangularSelection?: any;
|
||||
crosshairCursor?: any;
|
||||
highlightActiveLine?: any;
|
||||
highlightActiveLineGutter?: any;
|
||||
indentWithTab?: any;
|
||||
indentUnit?: any;
|
||||
autocompletion?: any;
|
||||
completionKeymap?: any;
|
||||
closeBrackets?: any;
|
||||
closeBracketsKeymap?: any;
|
||||
searchKeymap?: any;
|
||||
highlightSelectionMatches?: any;
|
||||
lintKeymap?: any;
|
||||
EditorState_allowMultipleSelections?: any;
|
||||
EditorView_lineWrapping?: any;
|
||||
EditorView_editable?: any;
|
||||
EditorView_contentAttributes?: any;
|
||||
bracketMatching?: any;
|
||||
foldGutter?: any;
|
||||
foldKeymap?: any;
|
||||
indentOnInput?: any;
|
||||
languages?: any;
|
||||
oneDark?: any;
|
||||
placeholderExt?: any;
|
||||
EditorView: any;
|
||||
EditorState: any;
|
||||
basicSetup?: any;
|
||||
markdown?: any;
|
||||
markdownLanguage?: any;
|
||||
keymap?: any;
|
||||
defaultKeymap?: any;
|
||||
history?: any;
|
||||
historyKeymap?: any;
|
||||
lineNumbers?: any;
|
||||
highlightSpecialChars?: any;
|
||||
drawSelection?: any;
|
||||
dropCursor?: any;
|
||||
rectangularSelection?: any;
|
||||
crosshairCursor?: any;
|
||||
highlightActiveLine?: any;
|
||||
highlightActiveLineGutter?: any;
|
||||
indentWithTab?: any;
|
||||
indentUnit?: any;
|
||||
autocompletion?: any;
|
||||
completionKeymap?: any;
|
||||
closeBrackets?: any;
|
||||
closeBracketsKeymap?: any;
|
||||
searchKeymap?: any;
|
||||
highlightSelectionMatches?: any;
|
||||
lintKeymap?: any;
|
||||
EditorState_allowMultipleSelections?: any;
|
||||
EditorView_lineWrapping?: any;
|
||||
EditorView_editable?: any;
|
||||
EditorView_contentAttributes?: any;
|
||||
bracketMatching?: any;
|
||||
foldGutter?: any;
|
||||
foldKeymap?: any;
|
||||
indentOnInput?: any;
|
||||
languages?: any;
|
||||
oneDark?: any;
|
||||
placeholderExt?: any;
|
||||
} | null;
|
||||
|
||||
const GLOBAL_KEY = '__cm_singleton_modules_v1';
|
||||
|
||||
export async function ensureCodeMirrorModules(): Promise<CMCache> {
|
||||
if (!browser) return null;
|
||||
if (!browser) return null;
|
||||
|
||||
// Use a single global object so HMR/multiple module copies reuse same instance
|
||||
const globalAny = globalThis as any;
|
||||
if (globalAny[GLOBAL_KEY]) return globalAny[GLOBAL_KEY] as CMCache;
|
||||
// Use a single global object so HMR/multiple module copies reuse same instance
|
||||
const globalAny = globalThis as any;
|
||||
if (globalAny[GLOBAL_KEY]) return globalAny[GLOBAL_KEY] as CMCache;
|
||||
|
||||
const [
|
||||
viewMod,
|
||||
stateMod,
|
||||
basicSetupMod,
|
||||
markdownMod,
|
||||
commandsMod,
|
||||
languageMod,
|
||||
autocompleteMod,
|
||||
searchMod,
|
||||
lintMod,
|
||||
themeOneDarkMod
|
||||
] = await Promise.all([
|
||||
import('@codemirror/view'),
|
||||
import('@codemirror/state'),
|
||||
import('@codemirror/basic-setup'),
|
||||
import('@codemirror/lang-markdown'),
|
||||
import('@codemirror/commands'),
|
||||
import('@codemirror/language'),
|
||||
import('@codemirror/autocomplete'),
|
||||
import('@codemirror/search'),
|
||||
import('@codemirror/lint'),
|
||||
import('@codemirror/theme-one-dark')
|
||||
]);
|
||||
const [
|
||||
viewMod,
|
||||
stateMod,
|
||||
basicSetupMod,
|
||||
markdownMod,
|
||||
commandsMod,
|
||||
languageMod,
|
||||
autocompleteMod,
|
||||
searchMod,
|
||||
lintMod,
|
||||
themeOneDarkMod
|
||||
] = await Promise.all([
|
||||
import('@codemirror/view'),
|
||||
import('@codemirror/state'),
|
||||
import('@codemirror/basic-setup'),
|
||||
import('@codemirror/lang-markdown'),
|
||||
import('@codemirror/commands'),
|
||||
import('@codemirror/language'),
|
||||
import('@codemirror/autocomplete'),
|
||||
import('@codemirror/search'),
|
||||
import('@codemirror/lint'),
|
||||
import('@codemirror/theme-one-dark')
|
||||
]);
|
||||
|
||||
const cache: CMCache = {
|
||||
EditorView: viewMod.EditorView,
|
||||
keymap: viewMod.keymap,
|
||||
lineNumbers: viewMod.lineNumbers,
|
||||
highlightSpecialChars: viewMod.highlightSpecialChars,
|
||||
drawSelection: viewMod.drawSelection,
|
||||
dropCursor: viewMod.dropCursor,
|
||||
rectangularSelection: viewMod.rectangularSelection,
|
||||
crosshairCursor: viewMod.crosshairCursor,
|
||||
highlightActiveLine: viewMod.highlightActiveLine,
|
||||
highlightActiveLineGutter: viewMod.highlightActiveLineGutter,
|
||||
EditorView_lineWrapping: viewMod.EditorView.lineWrapping,
|
||||
EditorView_editable: viewMod.EditorView.editable,
|
||||
EditorView_contentAttributes: viewMod.EditorView.contentAttributes,
|
||||
placeholderExt: viewMod.placeholder,
|
||||
const cache: CMCache = {
|
||||
EditorView: viewMod.EditorView,
|
||||
keymap: viewMod.keymap,
|
||||
lineNumbers: viewMod.lineNumbers,
|
||||
highlightSpecialChars: viewMod.highlightSpecialChars,
|
||||
drawSelection: viewMod.drawSelection,
|
||||
dropCursor: viewMod.dropCursor,
|
||||
rectangularSelection: viewMod.rectangularSelection,
|
||||
crosshairCursor: viewMod.crosshairCursor,
|
||||
highlightActiveLine: viewMod.highlightActiveLine,
|
||||
highlightActiveLineGutter: viewMod.highlightActiveLineGutter,
|
||||
EditorView_lineWrapping: viewMod.EditorView.lineWrapping,
|
||||
EditorView_editable: viewMod.EditorView.editable,
|
||||
EditorView_contentAttributes: viewMod.EditorView.contentAttributes,
|
||||
placeholderExt: viewMod.placeholder,
|
||||
|
||||
EditorState: stateMod.EditorState,
|
||||
EditorSelection: stateMod.EditorSelection,
|
||||
EditorState_allowMultipleSelections: stateMod.EditorState.allowMultipleSelections,
|
||||
EditorState_readOnly: stateMod.EditorState.readOnly,
|
||||
EditorState: stateMod.EditorState,
|
||||
EditorSelection: stateMod.EditorSelection,
|
||||
EditorState_allowMultipleSelections: stateMod.EditorState.allowMultipleSelections,
|
||||
EditorState_readOnly: stateMod.EditorState.readOnly,
|
||||
|
||||
basicSetup: basicSetupMod?.basicSetup,
|
||||
basicSetup: basicSetupMod?.basicSetup,
|
||||
|
||||
markdown: markdownMod?.markdown,
|
||||
markdownLanguage: markdownMod?.markdownLanguage,
|
||||
languages: languageMod?.languages, // From @codemirror/language-data, often re-exported by @codemirror/language
|
||||
markdown: markdownMod?.markdown,
|
||||
markdownLanguage: markdownMod?.markdownLanguage,
|
||||
languages: languageMod?.languages, // From @codemirror/language-data, often re-exported by @codemirror/language
|
||||
|
||||
defaultKeymap: (commandsMod && commandsMod.defaultKeymap) || [],
|
||||
history: commandsMod?.history,
|
||||
historyKeymap: commandsMod?.historyKeymap || [],
|
||||
indentWithTab: commandsMod?.indentWithTab,
|
||||
defaultKeymap: (commandsMod && commandsMod.defaultKeymap) || [],
|
||||
history: commandsMod?.history,
|
||||
historyKeymap: commandsMod?.historyKeymap || [],
|
||||
indentWithTab: commandsMod?.indentWithTab,
|
||||
|
||||
indentUnit: languageMod?.indentUnit,
|
||||
indentOnInput: languageMod?.indentOnInput,
|
||||
bracketMatching: languageMod?.bracketMatching,
|
||||
foldGutter: languageMod?.foldGutter,
|
||||
foldKeymap: languageMod?.foldKeymap,
|
||||
indentUnit: languageMod?.indentUnit,
|
||||
indentOnInput: languageMod?.indentOnInput,
|
||||
bracketMatching: languageMod?.bracketMatching,
|
||||
foldGutter: languageMod?.foldGutter,
|
||||
foldKeymap: languageMod?.foldKeymap,
|
||||
|
||||
autocompletion: autocompleteMod?.autocompletion,
|
||||
completionKeymap: autocompleteMod?.completionKeymap,
|
||||
closeBrackets: autocompleteMod?.closeBrackets,
|
||||
closeBracketsKeymap: autocompleteMod?.closeBracketsKeymap,
|
||||
autocompletion: autocompleteMod?.autocompletion,
|
||||
completionKeymap: autocompleteMod?.completionKeymap,
|
||||
closeBrackets: autocompleteMod?.closeBrackets,
|
||||
closeBracketsKeymap: autocompleteMod?.closeBracketsKeymap,
|
||||
|
||||
searchKeymap: searchMod?.searchKeymap,
|
||||
highlightSelectionMatches: searchMod?.highlightSelectionMatches,
|
||||
searchKeymap: searchMod?.searchKeymap,
|
||||
highlightSelectionMatches: searchMod?.highlightSelectionMatches,
|
||||
|
||||
lintKeymap: lintMod?.lintKeymap,
|
||||
lintKeymap: lintMod?.lintKeymap,
|
||||
|
||||
oneDark: themeOneDarkMod?.oneDark
|
||||
};
|
||||
oneDark: themeOneDarkMod?.oneDark
|
||||
};
|
||||
|
||||
globalAny[GLOBAL_KEY] = cache;
|
||||
return cache;
|
||||
globalAny[GLOBAL_KEY] = cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
@@ -1,447 +1,450 @@
|
||||
<script lang="ts">
|
||||
// *** Import Svelte core
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
// *** Import Svelte core
|
||||
import { createEventDispatcher, onMount } from 'svelte';
|
||||
|
||||
// *** Import Aether core variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { api } from '$lib/api';
|
||||
// import { update_ae_obj_id_crud } from '$lib/ae_core/core__crud_generic';
|
||||
import { update_ae_obj } from '$lib/ae_core/core__crud_generic';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
// *** Import Aether core variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { api } from '$lib/api';
|
||||
// import { update_ae_obj_id_crud } from '$lib/ae_core/core__crud_generic';
|
||||
import { update_ae_obj } from '$lib/ae_core/core__crud_generic';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
|
||||
// *** Import Aether core components
|
||||
// *** Import Aether module variables and functions
|
||||
// *** Import Aether module components
|
||||
// *** Import Aether core components
|
||||
// *** Import Aether module variables and functions
|
||||
// *** Import Aether module components
|
||||
|
||||
// *** Export/Exposed variables and functions for component
|
||||
export let log_lvl: number = 0;
|
||||
export let trigger_patch: any = null;
|
||||
export let api_cfg: key_val = { api_crud_super_key: null };
|
||||
// export let api_crud_super_key: null|string = api_cfg.api_crud_super_key;
|
||||
export let object_type: string;
|
||||
export let object_id: string;
|
||||
export let field_name: string;
|
||||
export let field_type: string = 'text'; // button, text, textarea, template (older method), select (in progress method)
|
||||
export let field_value: any;
|
||||
export let allow_null: boolean = false;
|
||||
export let select_option_li: key_val = {};
|
||||
export let val_empty_is_null: boolean = false; // This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
export let edit_label: string = 'Edit';
|
||||
export let display_inline: boolean = false;
|
||||
export let display_block_edit: boolean = false;
|
||||
// *** Export/Exposed variables and functions for component
|
||||
export let log_lvl: number = 0;
|
||||
export let trigger_patch: any = null;
|
||||
export let api_cfg: key_val = { api_crud_super_key: null };
|
||||
// export let api_crud_super_key: null|string = api_cfg.api_crud_super_key;
|
||||
export let object_type: string;
|
||||
export let object_id: string;
|
||||
export let field_name: string;
|
||||
export let field_type: string = 'text'; // button, text, textarea, template (older method), select (in progress method)
|
||||
export let field_value: any;
|
||||
export let allow_null: boolean = false;
|
||||
export let select_option_li: key_val = {};
|
||||
export let val_empty_is_null: boolean = false; // This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
export let edit_label: string = 'Edit';
|
||||
export let display_inline: boolean = false;
|
||||
export let display_block_edit: boolean = false;
|
||||
|
||||
export let textarea_cols: number = 80;
|
||||
export let textarea_rows: number = 5;
|
||||
export let textarea_cols: number = 80;
|
||||
export let textarea_rows: number = 5;
|
||||
|
||||
// export let input_field_template: null|object = null;
|
||||
// export let input_field_template: null|object = null;
|
||||
|
||||
export let hide_edit_btn = false;
|
||||
export let outline_element = false;
|
||||
export let show_crud = false;
|
||||
export let btn_label = null; // '<span class="fas fa-check mx-1"></span> Save'; // PATCH
|
||||
export let hide_edit_btn = false;
|
||||
export let outline_element = false;
|
||||
export let show_crud = false;
|
||||
export let btn_label = null; // '<span class="fas fa-check mx-1"></span> Save'; // PATCH
|
||||
|
||||
// export let show_field_name = true;
|
||||
// export let show_original_value = true;
|
||||
// export let trim_string = false;
|
||||
// export let remove_breaks = false;
|
||||
// export let show_field_name = true;
|
||||
// export let show_original_value = true;
|
||||
// export let trim_string = false;
|
||||
// export let remove_breaks = false;
|
||||
|
||||
export let class_li: string = '';
|
||||
export let class_li: string = '';
|
||||
|
||||
// *** Set initial variables
|
||||
let ae_promises: key_val = {}; // Promise<any>;
|
||||
let patch_result: null | Promise<any> | key_val | string;
|
||||
// *** Set initial variables
|
||||
let ae_promises: key_val = {}; // Promise<any>;
|
||||
let patch_result: null | Promise<any> | key_val | string;
|
||||
|
||||
let original_field_value = field_value;
|
||||
let original_field_value = field_value;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
onMount(() => {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`Element AE CRUD: Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; Field Value: ${field_value} (Original: ${original_field_value})`
|
||||
);
|
||||
// ; Super Key: ${api_crud_super_key}
|
||||
}
|
||||
});
|
||||
onMount(() => {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`Element AE CRUD: Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; Field Value: ${field_value} (Original: ${original_field_value})`
|
||||
);
|
||||
// ; Super Key: ${api_crud_super_key}
|
||||
}
|
||||
});
|
||||
|
||||
$: if (trigger_patch == true) {
|
||||
console.log('AE CRUD: Patch triggered!');
|
||||
trigger_patch = null;
|
||||
handle_obj_field_patch(field_value);
|
||||
}
|
||||
$: if (trigger_patch == true) {
|
||||
console.log('AE CRUD: Patch triggered!');
|
||||
trigger_patch = null;
|
||||
handle_obj_field_patch(field_value);
|
||||
}
|
||||
|
||||
// Updated 2024-03-22
|
||||
async function handle_obj_field_patch(new_field_value: any) {
|
||||
console.log('*** handle_obj_field_patch() ***');
|
||||
// Updated 2024-03-22
|
||||
async function handle_obj_field_patch(new_field_value: any) {
|
||||
console.log('*** handle_obj_field_patch() ***');
|
||||
|
||||
patch_result = null;
|
||||
patch_result = null;
|
||||
|
||||
// This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
if (val_empty_is_null && new_field_value == '') {
|
||||
new_field_value = null;
|
||||
}
|
||||
// This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
if (val_empty_is_null && new_field_value == '') {
|
||||
new_field_value = null;
|
||||
}
|
||||
|
||||
// NOTE: Is this needed? The field_name, field_value, and fields parameters for update_ae_obj_id_crud() already take care of the data portion. They are added to data_list object as part of the JSON request.
|
||||
// NOTE: Currently this only handles one field and value at a time. This may need to be changed in the future to use the "fields" parameter as well.
|
||||
// let patch_data = {}
|
||||
// NOTE: Is this needed? The field_name, field_value, and fields parameters for update_ae_obj_id_crud() already take care of the data portion. They are added to data_list object as part of the JSON request.
|
||||
// NOTE: Currently this only handles one field and value at a time. This may need to be changed in the future to use the "fields" parameter as well.
|
||||
// let patch_data = {}
|
||||
|
||||
// if (remove_breaks) {
|
||||
// patch_data['field_value'] = field_value.replace(/(\r\n|\n|\r)/gm, "");
|
||||
// } else {
|
||||
// patch_data['field_value'] = field_value;
|
||||
// }
|
||||
// if (remove_breaks) {
|
||||
// patch_data['field_value'] = field_value.replace(/(\r\n|\n|\r)/gm, "");
|
||||
// } else {
|
||||
// patch_data['field_value'] = field_value;
|
||||
// }
|
||||
|
||||
// patch_data[field_name] = field_value;
|
||||
// console.log(patch_data);
|
||||
// patch_data[field_name] = field_value;
|
||||
// console.log(patch_data);
|
||||
|
||||
// let params = {};
|
||||
// let params = {};
|
||||
|
||||
ae_promises.api_update__ae_obj = core_func
|
||||
.handle_update_ae_obj_id_crud({
|
||||
api_cfg: api_cfg,
|
||||
object_type: object_type,
|
||||
object_id: object_id,
|
||||
field_name: field_name,
|
||||
new_field_value: new_field_value,
|
||||
params: {},
|
||||
try_cache: false,
|
||||
log_lvl: 0
|
||||
})
|
||||
.then(function (results) {
|
||||
console.log('Field PATCH Promise', results);
|
||||
ae_promises.api_update__ae_obj = core_func
|
||||
.handle_update_ae_obj_id_crud({
|
||||
api_cfg: api_cfg,
|
||||
object_type: object_type,
|
||||
object_id: object_id,
|
||||
field_name: field_name,
|
||||
new_field_value: new_field_value,
|
||||
params: {},
|
||||
try_cache: false,
|
||||
log_lvl: 0
|
||||
})
|
||||
.then(function (results) {
|
||||
console.log('Field PATCH Promise', results);
|
||||
|
||||
if (results) {
|
||||
console.log(
|
||||
`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Original Field Value: ${original_field_value}`
|
||||
);
|
||||
patch_result = 'PATCH complete';
|
||||
original_field_value = new_field_value;
|
||||
} else {
|
||||
console.log(
|
||||
`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Original Field Value: ${original_field_value}`
|
||||
);
|
||||
patch_result = 'PATCH failed';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('Something went wrong patching the record.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(function () {
|
||||
console.log('Field PATCH Promise finally');
|
||||
// This dispatch() must be under "finally".
|
||||
dispatch('ae_crud_updated', {
|
||||
type: object_type,
|
||||
id: object_id,
|
||||
field_name: field_name,
|
||||
field_value: new_field_value,
|
||||
original_value: original_field_value
|
||||
});
|
||||
});
|
||||
if (results) {
|
||||
console.log(
|
||||
`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Original Field Value: ${original_field_value}`
|
||||
);
|
||||
patch_result = 'PATCH complete';
|
||||
original_field_value = new_field_value;
|
||||
} else {
|
||||
console.log(
|
||||
`Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Original Field Value: ${original_field_value}`
|
||||
);
|
||||
patch_result = 'PATCH failed';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
console.log('Something went wrong patching the record.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(function () {
|
||||
console.log('Field PATCH Promise finally');
|
||||
// This dispatch() must be under "finally".
|
||||
dispatch('ae_crud_updated', {
|
||||
type: object_type,
|
||||
id: object_id,
|
||||
field_name: field_name,
|
||||
field_value: new_field_value,
|
||||
original_value: original_field_value
|
||||
});
|
||||
});
|
||||
|
||||
return ae_promises.api_update__ae_obj;
|
||||
}
|
||||
return ae_promises.api_update__ae_obj;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="{class_li} ae_crud" class:show_crud class:display_inline class:outline_element>
|
||||
<span class="field_viewing_wrapper">
|
||||
<slot></slot>
|
||||
<span class="field_viewing_wrapper">
|
||||
<slot></slot>
|
||||
|
||||
<button
|
||||
class="btn btn-sm font-normal preset-tonal-warning hover:preset-tonal-error border border-error-500 field_show_btn"
|
||||
class:hide_edit_btn
|
||||
class:show_crud
|
||||
on:dblclick={() => {
|
||||
show_crud = true;
|
||||
}}
|
||||
title="Double click to edit property"
|
||||
>
|
||||
<span class="fas fa-edit"></span>
|
||||
<span class="hidden">Edit</span>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
class="btn btn-sm font-normal preset-tonal-warning hover:preset-tonal-error border border-error-500 field_show_btn"
|
||||
class:hide_edit_btn
|
||||
class:show_crud
|
||||
on:dblclick={() => {
|
||||
show_crud = true;
|
||||
}}
|
||||
title="Double click to edit property"
|
||||
>
|
||||
<span class="fas fa-edit"></span>
|
||||
<span class="hidden">Edit</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<div
|
||||
class:display_block_edit
|
||||
class="field_editing_wrapper font-normal min-w-content w-100 max-w-full"
|
||||
>
|
||||
<!-- <span class="grow flex flex-row items-center justify-between"> -->
|
||||
<span class="hidden">
|
||||
{edit_label}
|
||||
</span>
|
||||
<div
|
||||
class:display_block_edit
|
||||
class="field_editing_wrapper font-normal min-w-content w-100 max-w-full"
|
||||
>
|
||||
<!-- <span class="grow flex flex-row items-center justify-between"> -->
|
||||
<span class="hidden">
|
||||
{edit_label}
|
||||
</span>
|
||||
|
||||
<button
|
||||
class="btn btn-md font-normal ae_btn_surface_outlined m-1"
|
||||
class:show_crud
|
||||
on:click={() => {
|
||||
show_crud = false;
|
||||
}}
|
||||
title="Close field editing"
|
||||
>
|
||||
<span class="fas fa-window-close"></span>
|
||||
<span class="hidden sm:inline">Close</span>
|
||||
</button>
|
||||
<!-- </span> -->
|
||||
<button
|
||||
class="btn btn-md font-normal ae_btn_surface_outlined m-1"
|
||||
class:show_crud
|
||||
on:click={() => {
|
||||
show_crud = false;
|
||||
}}
|
||||
title="Close field editing"
|
||||
>
|
||||
<span class="fas fa-window-close"></span>
|
||||
<span class="hidden sm:inline">Close</span>
|
||||
</button>
|
||||
<!-- </span> -->
|
||||
|
||||
<span class="field_value grow min-w-content max-w-full" class:show_crud>
|
||||
{#if field_type == 'template'}
|
||||
<!-- <Element_input_v2 {...input_field_template} bind:value={field_value} /> -->
|
||||
{:else if field_type == 'button'}
|
||||
<!-- <input type="button" bind:value={field_value}> -->
|
||||
{field_value}
|
||||
{:else if field_type == 'select'}
|
||||
<select bind:value={field_value} class="select">
|
||||
{#if select_option_li && Object.keys(select_option_li).length == 0}
|
||||
<option value="">-- not set --</option>
|
||||
{:else if select_option_li && Object.keys(select_option_li).length > 0}
|
||||
{#each Object.keys(select_option_li) as option}
|
||||
<option value={option}>{select_option_li[option]}</option>
|
||||
{/each}
|
||||
{:else}
|
||||
<option value="">-- no list --</option>
|
||||
{/if}
|
||||
</select>
|
||||
{:else if field_type == 'text'}
|
||||
<input bind:value={field_value} class="input ae_btn_surface min-w-64 w-96 max-w-full" />
|
||||
{:else if field_type == 'textarea'}
|
||||
<textarea
|
||||
bind:value={field_value}
|
||||
cols={textarea_cols}
|
||||
rows={textarea_rows}
|
||||
class="textarea"
|
||||
></textarea>
|
||||
{:else}
|
||||
<input bind:value={field_value} class="input w-fit" />
|
||||
{/if}
|
||||
{#if allow_null}
|
||||
<button
|
||||
class="btn btn-sm ae_btn_warning m-1"
|
||||
on:click={() => {
|
||||
field_value = null;
|
||||
}}
|
||||
title="Set value to NULL"
|
||||
>
|
||||
Ø NULL
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
<span class="field_value grow min-w-content max-w-full" class:show_crud>
|
||||
{#if field_type == 'template'}
|
||||
<!-- <Element_input_v2 {...input_field_template} bind:value={field_value} /> -->
|
||||
{:else if field_type == 'button'}
|
||||
<!-- <input type="button" bind:value={field_value}> -->
|
||||
{field_value}
|
||||
{:else if field_type == 'select'}
|
||||
<select bind:value={field_value} class="select">
|
||||
{#if select_option_li && Object.keys(select_option_li).length == 0}
|
||||
<option value="">-- not set --</option>
|
||||
{:else if select_option_li && Object.keys(select_option_li).length > 0}
|
||||
{#each Object.keys(select_option_li) as option}
|
||||
<option value={option}>{select_option_li[option]}</option>
|
||||
{/each}
|
||||
{:else}
|
||||
<option value="">-- no list --</option>
|
||||
{/if}
|
||||
</select>
|
||||
{:else if field_type == 'text'}
|
||||
<input
|
||||
bind:value={field_value}
|
||||
class="input ae_btn_surface min-w-64 w-96 max-w-full"
|
||||
/>
|
||||
{:else if field_type == 'textarea'}
|
||||
<textarea
|
||||
bind:value={field_value}
|
||||
cols={textarea_cols}
|
||||
rows={textarea_rows}
|
||||
class="textarea"
|
||||
></textarea>
|
||||
{:else}
|
||||
<input bind:value={field_value} class="input w-fit" />
|
||||
{/if}
|
||||
{#if allow_null}
|
||||
<button
|
||||
class="btn btn-sm ae_btn_warning m-1"
|
||||
on:click={() => {
|
||||
field_value = null;
|
||||
}}
|
||||
title="Set value to NULL"
|
||||
>
|
||||
Ø NULL
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<button
|
||||
class="btn btn-lg ae_btn_warning_outlined m-1"
|
||||
class:show_crud
|
||||
disabled={field_value == original_field_value}
|
||||
on:click={async () => {
|
||||
handle_obj_field_patch(field_value);
|
||||
}}
|
||||
title="Save new field value"
|
||||
>
|
||||
{#if field_value == original_field_value}
|
||||
{#if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
<!-- <span>{patch_result}</span> -->
|
||||
{:else if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-save mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-lg ae_btn_warning_outlined m-1"
|
||||
class:show_crud
|
||||
disabled={field_value == original_field_value}
|
||||
on:click={async () => {
|
||||
handle_obj_field_patch(field_value);
|
||||
}}
|
||||
title="Save new field value"
|
||||
>
|
||||
{#if field_value == original_field_value}
|
||||
{#if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
<!-- <span>{patch_result}</span> -->
|
||||
{:else if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-save mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<div class="field_patch_result" class:show_crud>
|
||||
{#await ae_promises.api_update__ae_obj}
|
||||
<span class="fas fa-spinner fa-spin mx-1"></span>
|
||||
<span>Processing...</span>
|
||||
{:then}
|
||||
{#if patch_result}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>{patch_result}</span>
|
||||
{:else}
|
||||
<!-- <div>Nothing to show yet...</div> -->
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field_patch_result" class:show_crud>
|
||||
{#await ae_promises.api_update__ae_obj}
|
||||
<span class="fas fa-spinner fa-spin mx-1"></span>
|
||||
<span>Processing...</span>
|
||||
{:then}
|
||||
{#if patch_result}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>{patch_result}</span>
|
||||
{:else}
|
||||
<!-- <div>Nothing to show yet...</div> -->
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* .ae_crud .field_editing_wrapper {
|
||||
/* .ae_crud .field_editing_wrapper {
|
||||
font-size: 1em;
|
||||
} */
|
||||
|
||||
/* BEGIN: Svelte CRUD (update) component */
|
||||
/* .ae_crud {
|
||||
/* BEGIN: Svelte CRUD (update) component */
|
||||
/* .ae_crud {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
} */
|
||||
|
||||
.ae_crud.display_inline {
|
||||
/* outline: solid thin red; */
|
||||
display: inline;
|
||||
}
|
||||
.ae_crud.display_inline {
|
||||
/* outline: solid thin red; */
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud .field_viewing_wrapper .field_show_btn {
|
||||
display: none;
|
||||
}
|
||||
.ae_crud.show_crud .field_viewing_wrapper .field_show_btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ae_crud.outline_element .field_viewing_wrapper {
|
||||
outline: dotted thin hsla(0, 50%, 50%, 0);
|
||||
transition: outline 3s 1s;
|
||||
}
|
||||
.ae_crud.outline_element .field_viewing_wrapper:hover {
|
||||
outline: dashed thin hsla(0, 50%, 50%, 0.9);
|
||||
transition: outline 1s 0.5s;
|
||||
}
|
||||
.ae_crud.outline_element .field_viewing_wrapper {
|
||||
outline: dotted thin hsla(0, 50%, 50%, 0);
|
||||
transition: outline 3s 1s;
|
||||
}
|
||||
.ae_crud.outline_element .field_viewing_wrapper:hover {
|
||||
outline: dashed thin hsla(0, 50%, 50%, 0.9);
|
||||
transition: outline 1s 0.5s;
|
||||
}
|
||||
|
||||
.ae_crud .field_viewing_wrapper .field_show_btn.hide_edit_btn {
|
||||
display: none;
|
||||
}
|
||||
.ae_crud .field_viewing_wrapper .field_show_btn.hide_edit_btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ae_crud .field_viewing_wrapper .field_show_btn {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
.ae_crud .field_viewing_wrapper .field_show_btn {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
opacity: 0.25;
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
opacity: 0.25;
|
||||
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 1s; /* no delay */
|
||||
transition-duration: 0.55s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 1s; /* no delay */
|
||||
transition-duration: 0.55s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.ae_crud .field_viewing_wrapper:hover .field_show_btn {
|
||||
/* outline: solid thin hsla(0,50%,50%,.9); */
|
||||
/* color: hsla(0,50%,50%,.9); */
|
||||
.ae_crud .field_viewing_wrapper:hover .field_show_btn {
|
||||
/* outline: solid thin hsla(0,50%,50%,.9); */
|
||||
/* color: hsla(0,50%,50%,.9); */
|
||||
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
|
||||
/* NOTE: transition when hover starts */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 0.25s; /* no delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
/* NOTE: transition when hover starts */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 0.25s; /* no delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.ae_crud .field_editing_wrapper {
|
||||
/* outline: dashed thin pink; */
|
||||
.ae_crud .field_editing_wrapper {
|
||||
/* outline: dashed thin pink; */
|
||||
|
||||
display: none;
|
||||
/* position: relative; */
|
||||
display: none;
|
||||
/* position: relative; */
|
||||
|
||||
/* contain: layout; */
|
||||
/* contain: size; */
|
||||
/* contain: none; */
|
||||
contain: content;
|
||||
/* contain: layout; */
|
||||
/* contain: size; */
|
||||
/* contain: none; */
|
||||
contain: content;
|
||||
|
||||
box-shadow: 0.5em 0.5em 0.75em 0.75em hsla(0, 0%, 0%, 0.5);
|
||||
box-shadow: 0.5em 0.5em 0.75em 0.75em hsla(0, 0%, 0%, 0.5);
|
||||
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
background-color: hsla(0, 0%, 50%, 0.5);
|
||||
border: dashed thin transparent;
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
background-color: hsla(0, 0%, 50%, 0.5);
|
||||
border: dashed thin transparent;
|
||||
|
||||
/* font-size: 1em; */
|
||||
/* line-height: 1em; */
|
||||
/* font-size: 1em; */
|
||||
/* line-height: 1em; */
|
||||
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: background-color, border-color, color, height, width;
|
||||
transition-delay: 0.75s; /* short delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: background-color, border-color, color, height, width;
|
||||
transition-delay: 0.75s; /* short delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud .field_editing_wrapper {
|
||||
/* display: initial; */
|
||||
display: block;
|
||||
contain: content;
|
||||
.ae_crud.show_crud .field_editing_wrapper {
|
||||
/* display: initial; */
|
||||
display: block;
|
||||
contain: content;
|
||||
|
||||
/* background-color: yellow; */
|
||||
background-color: hsla(60, 50%, 80%, 0.95);
|
||||
border: solid thin hsla(0, 50%, 50%, 0.5);
|
||||
border-radius: 0.5em;
|
||||
/* background-color: yellow; */
|
||||
background-color: hsla(60, 50%, 80%, 0.95);
|
||||
border: solid thin hsla(0, 50%, 50%, 0.5);
|
||||
border-radius: 0.5em;
|
||||
|
||||
height: auto;
|
||||
/* height: 100%; */
|
||||
max-height: 100%;
|
||||
height: auto;
|
||||
/* height: 100%; */
|
||||
max-height: 100%;
|
||||
|
||||
min-width: fit-content;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
min-width: fit-content;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
|
||||
/* NOTE: transition when hover starts */
|
||||
transition-property: background-color, border-color, height, width;
|
||||
transition-delay: 0.25s; /* no delay */
|
||||
transition-duration: 0.25s;
|
||||
transition-timing-function: linear;
|
||||
/* NOTE: transition when hover starts */
|
||||
transition-property: background-color, border-color, height, width;
|
||||
transition-delay: 0.25s; /* no delay */
|
||||
transition-duration: 0.25s;
|
||||
transition-timing-function: linear;
|
||||
|
||||
/* position: absolute; */
|
||||
/* position: fixed; */
|
||||
/* position: relative; */
|
||||
/* top: 1em; */
|
||||
/* left: 1em; */
|
||||
/* right: 1em; */
|
||||
/* bottom: 1em; */
|
||||
/* position: absolute; */
|
||||
/* position: fixed; */
|
||||
/* position: relative; */
|
||||
/* top: 1em; */
|
||||
/* left: 1em; */
|
||||
/* right: 1em; */
|
||||
/* bottom: 1em; */
|
||||
|
||||
z-index: 1;
|
||||
z-index: 1;
|
||||
|
||||
padding: 0.5em;
|
||||
}
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper:hover {
|
||||
background-color: hsla(60, 60%, 90%, 0.8);
|
||||
z-index: 55;
|
||||
}
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper:hover {
|
||||
background-color: hsla(60, 60%, 90%, 0.8);
|
||||
z-index: 55;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper {
|
||||
/* display: block; */
|
||||
display: inline-block;
|
||||
/* display: inline; */
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper {
|
||||
/* display: block; */
|
||||
display: inline-block;
|
||||
/* display: inline; */
|
||||
|
||||
box-shadow: initial;
|
||||
background-color: hsla(60, 50%, 80%, 0.4);
|
||||
box-shadow: initial;
|
||||
background-color: hsla(60, 50%, 80%, 0.4);
|
||||
|
||||
padding: 0.25em;
|
||||
padding: 0.25em;
|
||||
|
||||
position: initial;
|
||||
position: initial;
|
||||
|
||||
z-index: 0;
|
||||
z-index: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
|
||||
width: 30%;
|
||||
}
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper.display_block_edit {
|
||||
/* display: block; */
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper.display_block_edit {
|
||||
/* display: block; */
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
|
||||
flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ae_crud textarea {
|
||||
height: auto;
|
||||
}
|
||||
/* END: Svelte CRUD (update) component */
|
||||
.ae_crud textarea {
|
||||
height: auto;
|
||||
}
|
||||
/* END: Svelte CRUD (update) component */
|
||||
</style>
|
||||
|
||||
@@ -1,258 +1,258 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
api_cfg?: key_val;
|
||||
// export let api_crud_super_key: null|string = api_cfg.api_crud_super_key;
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
api_cfg?: key_val;
|
||||
// export let api_crud_super_key: null|string = api_cfg.api_crud_super_key;
|
||||
|
||||
trigger_patch?: any;
|
||||
patch_status?: string; // '', processing, complete, error
|
||||
patch_complete?: boolean | null | string; // null = not started, true = complete/success, false = error
|
||||
patch_result?: boolean | null | key_val; // Result of the patch operation
|
||||
trigger_patch?: any;
|
||||
patch_status?: string; // '', processing, complete, error
|
||||
patch_complete?: boolean | null | string; // null = not started, true = complete/success, false = error
|
||||
patch_result?: boolean | null | key_val; // Result of the patch operation
|
||||
|
||||
object_type: string;
|
||||
object_id: string;
|
||||
object_reload?: boolean;
|
||||
object_type: string;
|
||||
object_id: string;
|
||||
object_reload?: boolean;
|
||||
|
||||
field_name: string;
|
||||
field_type?: string; // button, text, textarea, template (older method), select (in progress method)
|
||||
field_name: string;
|
||||
field_type?: string; // button, text, textarea, template (older method), select (in progress method)
|
||||
|
||||
previous_field_value?: any;
|
||||
current_field_value?: any;
|
||||
new_field_value?: any;
|
||||
previous_field_value?: any;
|
||||
current_field_value?: any;
|
||||
new_field_value?: any;
|
||||
|
||||
allow_null?: boolean;
|
||||
select_option_kv?: key_val;
|
||||
val_empty_is_null?: boolean; // This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
allow_null?: boolean;
|
||||
select_option_kv?: key_val;
|
||||
val_empty_is_null?: boolean; // This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
|
||||
edit_label?: string;
|
||||
display_block?: boolean; // If true, the element will be displayed as a block element.
|
||||
// display_inline?: boolean;
|
||||
display_absolute_edit?: boolean; // If true, the edit form will be displayed in the top right corner of the element.
|
||||
// display_block_edit?: boolean;
|
||||
textarea_cols?: number;
|
||||
textarea_rows?: number;
|
||||
edit_label?: string;
|
||||
display_block?: boolean; // If true, the element will be displayed as a block element.
|
||||
// display_inline?: boolean;
|
||||
display_absolute_edit?: boolean; // If true, the edit form will be displayed in the top right corner of the element.
|
||||
// display_block_edit?: boolean;
|
||||
textarea_cols?: number;
|
||||
textarea_rows?: number;
|
||||
|
||||
// export let input_field_template: null|object = null;
|
||||
// export let input_field_template: null|object = null;
|
||||
|
||||
hide_element?: boolean; // This hides the entire custom element.
|
||||
hide_edit_btn?: boolean; // This only hides the edit button.
|
||||
// hide_edit_form?: boolean;
|
||||
show_edit_form?: boolean; // This is used if the parent needs to make the edit form visible.
|
||||
hide_element?: boolean; // This hides the entire custom element.
|
||||
hide_edit_btn?: boolean; // This only hides the edit button.
|
||||
// hide_edit_form?: boolean;
|
||||
show_edit_form?: boolean; // This is used if the parent needs to make the edit form visible.
|
||||
|
||||
outline_element?: boolean;
|
||||
outline_element?: boolean;
|
||||
|
||||
btn_label?: any; // '<span class="fas fa-check mx-1"></span> Save'; // PATCH
|
||||
// export let remove_breaks = false;
|
||||
class_li?: string;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
btn_label?: any; // '<span class="fas fa-check mx-1"></span> Save'; // PATCH
|
||||
// export let remove_breaks = false;
|
||||
class_li?: string;
|
||||
children?: import('svelte').Snippet;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
api_cfg = { api_crud_super_key: null },
|
||||
let {
|
||||
log_lvl = 0,
|
||||
api_cfg = { api_crud_super_key: null },
|
||||
|
||||
trigger_patch = null,
|
||||
patch_status = '',
|
||||
patch_complete = $bindable(null), // null = not started, true = complete/success, false = error
|
||||
patch_result = null,
|
||||
trigger_patch = null,
|
||||
patch_status = '',
|
||||
patch_complete = $bindable(null), // null = not started, true = complete/success, false = error
|
||||
patch_result = null,
|
||||
|
||||
object_type,
|
||||
object_id,
|
||||
object_reload = false,
|
||||
object_type,
|
||||
object_id,
|
||||
object_reload = false,
|
||||
|
||||
field_name,
|
||||
field_type = 'text',
|
||||
field_name,
|
||||
field_type = 'text',
|
||||
|
||||
previous_field_value = $bindable(null),
|
||||
current_field_value = null,
|
||||
new_field_value = current_field_value,
|
||||
previous_field_value = $bindable(null),
|
||||
current_field_value = null,
|
||||
new_field_value = current_field_value,
|
||||
|
||||
allow_null = false,
|
||||
select_option_kv = $bindable({}),
|
||||
val_empty_is_null = false, // If the value is empty (''), it will be set to null.
|
||||
allow_null = false,
|
||||
select_option_kv = $bindable({}),
|
||||
val_empty_is_null = false, // If the value is empty (''), it will be set to null.
|
||||
|
||||
edit_label = 'Edit',
|
||||
display_block = false,
|
||||
// display_inline = false,
|
||||
display_absolute_edit = false,
|
||||
// display_block_edit = false,
|
||||
textarea_cols = 80,
|
||||
textarea_rows = 5,
|
||||
edit_label = 'Edit',
|
||||
display_block = false,
|
||||
// display_inline = false,
|
||||
display_absolute_edit = false,
|
||||
// display_block_edit = false,
|
||||
textarea_cols = 80,
|
||||
textarea_rows = 5,
|
||||
|
||||
hide_element = $bindable(false),
|
||||
hide_edit_btn = false,
|
||||
// hide_edit_form = $bindable(true),
|
||||
show_edit_form = $bindable(),
|
||||
hide_element = $bindable(false),
|
||||
hide_edit_btn = false,
|
||||
// hide_edit_form = $bindable(true),
|
||||
show_edit_form = $bindable(),
|
||||
|
||||
outline_element = $bindable(false),
|
||||
outline_element = $bindable(false),
|
||||
|
||||
btn_label = null,
|
||||
class_li = '',
|
||||
children
|
||||
}: Props = $props();
|
||||
btn_label = null,
|
||||
class_li = '',
|
||||
children
|
||||
}: Props = $props();
|
||||
|
||||
// *** Import Svelte core
|
||||
import { browser } from '$app/environment';
|
||||
// *** Import Svelte core
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// *** Import Aether core variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { api } from '$lib/api';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
// *** Import Aether core variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { api } from '$lib/api';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
|
||||
// *** Import Aether core components
|
||||
// *** Import Aether module variables and functions
|
||||
// *** Import Aether module components
|
||||
// *** Import Aether core components
|
||||
// *** Import Aether module variables and functions
|
||||
// *** Import Aether module components
|
||||
|
||||
// export let show_field_name = true;
|
||||
// export let show_original_value = true;
|
||||
// export let trim_string = false;
|
||||
// export let show_field_name = true;
|
||||
// export let show_original_value = true;
|
||||
// export let trim_string = false;
|
||||
|
||||
// *** Set initial variables
|
||||
let ae_promises: key_val = $state({}); // Promise<any>;
|
||||
// let patch_result: null|Promise<any>|key_val|string = $state();
|
||||
// *** Set initial variables
|
||||
let ae_promises: key_val = $state({}); // Promise<any>;
|
||||
// let patch_result: null|Promise<any>|key_val|string = $state();
|
||||
|
||||
$effect(() => {
|
||||
if (browser) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`Element AE CRUD: Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; New Field Value: ${new_field_value} (Current: ${current_field_value})`
|
||||
);
|
||||
// ; Super Key: ${api_crud_super_key}
|
||||
}
|
||||
}
|
||||
$effect(() => {
|
||||
if (browser) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`Element AE CRUD: Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; New Field Value: ${new_field_value} (Current: ${current_field_value})`
|
||||
);
|
||||
// ; Super Key: ${api_crud_super_key}
|
||||
}
|
||||
}
|
||||
|
||||
// if (select_option_kv) {
|
||||
// console.log(select_option_kv);
|
||||
// }
|
||||
// if (select_option_kv) {
|
||||
// console.log(select_option_kv);
|
||||
// }
|
||||
|
||||
if (trigger_patch === true) {
|
||||
if (log_lvl) {
|
||||
console.log('AE CRUD: Patch triggered by trigger_patch = true');
|
||||
}
|
||||
trigger_patch = null;
|
||||
handle_obj_field_patch(new_field_value);
|
||||
if (trigger_patch === true) {
|
||||
if (log_lvl) {
|
||||
console.log('AE CRUD: Patch triggered by trigger_patch = true');
|
||||
}
|
||||
trigger_patch = null;
|
||||
handle_obj_field_patch(new_field_value);
|
||||
|
||||
// if (new_field_value !== current_field_value) {
|
||||
// if (log_lvl > 1) {
|
||||
// console.log(`AE CRUD: field_value changed from ${current_field_value} to ${new_field_value}`);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
});
|
||||
// if (new_field_value !== current_field_value) {
|
||||
// if (log_lvl > 1) {
|
||||
// console.log(`AE CRUD: field_value changed from ${current_field_value} to ${new_field_value}`);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
});
|
||||
|
||||
// Updated 2024-03-22
|
||||
async function handle_obj_field_patch(new_field_value: any) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`AE CRUD: Patching Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; New Field Value: ${new_field_value}; Current Field Value: ${current_field_value}`
|
||||
);
|
||||
// ; Super Key: ${api_crud_super_key}
|
||||
}
|
||||
// Updated 2024-03-22
|
||||
async function handle_obj_field_patch(new_field_value: any) {
|
||||
if (log_lvl) {
|
||||
console.log(
|
||||
`AE CRUD: Patching Object Type: ${object_type}; Object ID: ${object_id}; Field Name: ${field_name}; New Field Value: ${new_field_value}; Current Field Value: ${current_field_value}`
|
||||
);
|
||||
// ; Super Key: ${api_crud_super_key}
|
||||
}
|
||||
|
||||
patch_status = 'Processing...';
|
||||
patch_complete = null;
|
||||
patch_result = null;
|
||||
patch_status = 'Processing...';
|
||||
patch_complete = null;
|
||||
patch_result = null;
|
||||
|
||||
// This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
if (val_empty_is_null && new_field_value == '') {
|
||||
new_field_value = null;
|
||||
}
|
||||
// This was added to help with a select option list. If the value is empty (''), it will be set to null.
|
||||
if (val_empty_is_null && new_field_value == '') {
|
||||
new_field_value = null;
|
||||
}
|
||||
|
||||
// NOTE: Is this needed? The field_name, field_value, and fields parameters for update_ae_obj_id_crud() already take care of the data portion. They are added to data_list object as part of the JSON request.
|
||||
// NOTE: Currently this only handles one field and value at a time. This may need to be changed in the future to use the "fields" parameter as well.
|
||||
// let patch_data = {}
|
||||
// NOTE: Is this needed? The field_name, field_value, and fields parameters for update_ae_obj_id_crud() already take care of the data portion. They are added to data_list object as part of the JSON request.
|
||||
// NOTE: Currently this only handles one field and value at a time. This may need to be changed in the future to use the "fields" parameter as well.
|
||||
// let patch_data = {}
|
||||
|
||||
// if (remove_breaks) {
|
||||
// patch_data['field_value'] = field_value.replace(/(\r\n|\n|\r)/gm, "");
|
||||
// } else {
|
||||
// patch_data['field_value'] = field_value;
|
||||
// }
|
||||
// if (remove_breaks) {
|
||||
// patch_data['field_value'] = field_value.replace(/(\r\n|\n|\r)/gm, "");
|
||||
// } else {
|
||||
// patch_data['field_value'] = field_value;
|
||||
// }
|
||||
|
||||
// patch_data[field_name] = field_value;
|
||||
// console.log(patch_data);
|
||||
// patch_data[field_name] = field_value;
|
||||
// console.log(patch_data);
|
||||
|
||||
// let params = {};
|
||||
// let params = {};
|
||||
|
||||
ae_promises.api_update__ae_obj = core_func
|
||||
.update_ae_obj_id_crud_v2({
|
||||
api_cfg: api_cfg,
|
||||
object_type: object_type,
|
||||
object_id: object_id,
|
||||
object_reload: object_reload,
|
||||
field_name: field_name,
|
||||
new_field_value: new_field_value,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (results) {
|
||||
// console.log('Field PATCH Promise', results);
|
||||
ae_promises.api_update__ae_obj = core_func
|
||||
.update_ae_obj_id_crud_v2({
|
||||
api_cfg: api_cfg,
|
||||
object_type: object_type,
|
||||
object_id: object_id,
|
||||
object_reload: object_reload,
|
||||
field_name: field_name,
|
||||
new_field_value: new_field_value,
|
||||
log_lvl: log_lvl
|
||||
})
|
||||
.then(function (results) {
|
||||
// console.log('Field PATCH Promise', results);
|
||||
|
||||
if (results) {
|
||||
// console.log(`Patched - Field Name: ${field_name} with New Field Value: ${new_field_value}; Original Field Value: ${current_field_value}`);
|
||||
patch_status = 'PATCH complete';
|
||||
current_field_value = new_field_value;
|
||||
} else {
|
||||
console.log(
|
||||
`Not Patched - Field Name: ${field_name} with New Field Value: ${new_field_value}; Original Field Value: ${current_field_value}`
|
||||
);
|
||||
patch_status = 'PATCH failed';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
patch_status = 'Error during PATCH';
|
||||
console.log('Something went wrong patching the record.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(function () {
|
||||
// console.log('Field PATCH Promise finally');
|
||||
if (patch_status != 'PATCH complete') {
|
||||
patch_status = 'Error during PATCH';
|
||||
patch_complete = false;
|
||||
patch_result = false;
|
||||
} else {
|
||||
// patch_complete = true;
|
||||
patch_complete = object_id; // Return the object ID that was patched
|
||||
patch_result = {
|
||||
type: object_type,
|
||||
id: object_id,
|
||||
field_name: field_name,
|
||||
field_value: new_field_value,
|
||||
original_value: current_field_value
|
||||
};
|
||||
}
|
||||
});
|
||||
if (results) {
|
||||
// console.log(`Patched - Field Name: ${field_name} with New Field Value: ${new_field_value}; Original Field Value: ${current_field_value}`);
|
||||
patch_status = 'PATCH complete';
|
||||
current_field_value = new_field_value;
|
||||
} else {
|
||||
console.log(
|
||||
`Not Patched - Field Name: ${field_name} with New Field Value: ${new_field_value}; Original Field Value: ${current_field_value}`
|
||||
);
|
||||
patch_status = 'PATCH failed';
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.catch(function (error: any) {
|
||||
patch_status = 'Error during PATCH';
|
||||
console.log('Something went wrong patching the record.');
|
||||
console.log(error);
|
||||
return false;
|
||||
})
|
||||
.finally(function () {
|
||||
// console.log('Field PATCH Promise finally');
|
||||
if (patch_status != 'PATCH complete') {
|
||||
patch_status = 'Error during PATCH';
|
||||
patch_complete = false;
|
||||
patch_result = false;
|
||||
} else {
|
||||
// patch_complete = true;
|
||||
patch_complete = object_id; // Return the object ID that was patched
|
||||
patch_result = {
|
||||
type: object_type,
|
||||
id: object_id,
|
||||
field_name: field_name,
|
||||
field_value: new_field_value,
|
||||
original_value: current_field_value
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return ae_promises.api_update__ae_obj;
|
||||
}
|
||||
return ae_promises.api_update__ae_obj;
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- relative -->
|
||||
<div
|
||||
class="{class_li} ae_crud
|
||||
class="{class_li} ae_crud
|
||||
font-normal
|
||||
transition-all duration-300 ease-in-out
|
||||
relative
|
||||
"
|
||||
class:hidden={hide_element}
|
||||
class:block={display_block}
|
||||
class:inline-block={!display_block}
|
||||
class:outline_element
|
||||
class:hidden={hide_element}
|
||||
class:block={display_block}
|
||||
class:inline-block={!display_block}
|
||||
class:outline_element
|
||||
>
|
||||
{@render children?.()}
|
||||
{@render children?.()}
|
||||
|
||||
<span
|
||||
class="field_viewing_wrapper
|
||||
<span
|
||||
class="field_viewing_wrapper
|
||||
"
|
||||
>
|
||||
<!-- {@render children?.()} -->
|
||||
>
|
||||
<!-- {@render children?.()} -->
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class:hidden={show_edit_form || hide_edit_btn}
|
||||
class="
|
||||
<button
|
||||
type="button"
|
||||
class:hidden={show_edit_form || hide_edit_btn}
|
||||
class="
|
||||
btn btn-icon
|
||||
text-xs
|
||||
m-0 px-0.5
|
||||
@@ -261,26 +261,26 @@
|
||||
opacity-50 hover:opacity-100
|
||||
transition-all
|
||||
"
|
||||
ondblclick={() => {
|
||||
// hide_edit_btn = true;
|
||||
// hide_edit_form = false;
|
||||
show_edit_form = true;
|
||||
}}
|
||||
title="Double click to edit property"
|
||||
>
|
||||
<span class="fas fa-edit m-0 p-0"></span>
|
||||
<span class="hidden">Edit</span>
|
||||
</button>
|
||||
</span>
|
||||
ondblclick={() => {
|
||||
// hide_edit_btn = true;
|
||||
// hide_edit_form = false;
|
||||
show_edit_form = true;
|
||||
}}
|
||||
title="Double click to edit property"
|
||||
>
|
||||
<span class="fas fa-edit m-0 p-0"></span>
|
||||
<span class="hidden">Edit</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<!-- class:display_block={display_block} -->
|
||||
<div
|
||||
class:hidden={!show_edit_form}
|
||||
class:absolute={display_absolute_edit}
|
||||
class:top-0={display_absolute_edit}
|
||||
class:right-0={display_absolute_edit}
|
||||
class:drop-shadow-2xl={display_absolute_edit}
|
||||
class="field_editing_wrapper_v2
|
||||
<!-- class:display_block={display_block} -->
|
||||
<div
|
||||
class:hidden={!show_edit_form}
|
||||
class:absolute={display_absolute_edit}
|
||||
class:top-0={display_absolute_edit}
|
||||
class:right-0={display_absolute_edit}
|
||||
class:drop-shadow-2xl={display_absolute_edit}
|
||||
class="field_editing_wrapper_v2
|
||||
border-2 border-dashed hover:border-solid
|
||||
border-pink-400 dark:border-pink-600
|
||||
rounded-md
|
||||
@@ -295,257 +295,260 @@
|
||||
space-y-2
|
||||
transition-all duration-300 ease-in-out
|
||||
"
|
||||
>
|
||||
<span class="grow flex flex-row items-center justify-between">
|
||||
<span class="hidden md:inline font-semibold text-lg">
|
||||
{edit_label}
|
||||
</span>
|
||||
>
|
||||
<span class="grow flex flex-row items-center justify-between">
|
||||
<span class="hidden md:inline font-semibold text-lg">
|
||||
{edit_label}
|
||||
</span>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-md ae_btn_surface_outlined m-1"
|
||||
onclick={() => {
|
||||
// hide_edit_btn = false;
|
||||
// hide_edit_form = true;
|
||||
show_edit_form = false;
|
||||
}}
|
||||
title="Close field editing. This does not save any changes."
|
||||
>
|
||||
<span class="fas fa-window-close"></span>
|
||||
<span class="hidden sm:inline">Close</span>
|
||||
</button>
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-md ae_btn_surface_outlined m-1"
|
||||
onclick={() => {
|
||||
// hide_edit_btn = false;
|
||||
// hide_edit_form = true;
|
||||
show_edit_form = false;
|
||||
}}
|
||||
title="Close field editing. This does not save any changes."
|
||||
>
|
||||
<span class="fas fa-window-close"></span>
|
||||
<span class="hidden sm:inline">Close</span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
New value: {new_field_value}
|
||||
</span>
|
||||
<span>
|
||||
New value: {new_field_value}
|
||||
</span>
|
||||
|
||||
<span
|
||||
class="field_value
|
||||
<span
|
||||
class="field_value
|
||||
grow
|
||||
min-w-fit w-full max-w-fit
|
||||
flex flex-row flex-wrap items-center justify-center gap-1
|
||||
"
|
||||
>
|
||||
{#if field_type == 'template'}
|
||||
<!-- <Element_input_v2 {...input_field_template} bind:value={field_value} /> -->
|
||||
{:else if field_type == 'button'}
|
||||
<!-- <input type="button" bind:value={field_value}> -->
|
||||
{new_field_value}
|
||||
{:else if field_type == 'select'}
|
||||
<select
|
||||
bind:value={new_field_value}
|
||||
class="
|
||||
>
|
||||
{#if field_type == 'template'}
|
||||
<!-- <Element_input_v2 {...input_field_template} bind:value={field_value} /> -->
|
||||
{:else if field_type == 'button'}
|
||||
<!-- <input type="button" bind:value={field_value}> -->
|
||||
{new_field_value}
|
||||
{:else if field_type == 'select'}
|
||||
<select
|
||||
bind:value={new_field_value}
|
||||
class="
|
||||
select
|
||||
p-1
|
||||
min-w-fit w-full
|
||||
border border-gray-300 dark:border-gray-600
|
||||
"
|
||||
>
|
||||
{#if select_option_kv && Object.keys(select_option_kv).length == 0}
|
||||
<option value="">-- not set --</option>
|
||||
{:else if select_option_kv && Object.keys(select_option_kv).length > 0}
|
||||
{#each Object.keys(select_option_kv) as option}
|
||||
<option value={option}>{select_option_kv[option]} {option}</option>
|
||||
{/each}
|
||||
{:else}
|
||||
<option value="">-- no list --</option>
|
||||
{/if}
|
||||
</select>
|
||||
{:else if field_type == 'text'}
|
||||
<input bind:value={new_field_value} class="input ae_btn_surface min-w-64 w-96 max-w-full" />
|
||||
{:else if field_type == 'textarea'}
|
||||
<textarea
|
||||
bind:value={new_field_value}
|
||||
cols={textarea_cols}
|
||||
rows={textarea_rows}
|
||||
class="textarea"
|
||||
></textarea>
|
||||
{:else}
|
||||
<input bind:value={new_field_value} class="input w-fit" />
|
||||
{/if}
|
||||
{#if allow_null}
|
||||
<button
|
||||
class="btn btn-sm ae_btn_warning m-1"
|
||||
onclick={() => {
|
||||
new_field_value = null;
|
||||
}}
|
||||
title="Set value to NULL"
|
||||
>
|
||||
Ø NULL
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
>
|
||||
{#if select_option_kv && Object.keys(select_option_kv).length == 0}
|
||||
<option value="">-- not set --</option>
|
||||
{:else if select_option_kv && Object.keys(select_option_kv).length > 0}
|
||||
{#each Object.keys(select_option_kv) as option}
|
||||
<option value={option}>{select_option_kv[option]} {option}</option>
|
||||
{/each}
|
||||
{:else}
|
||||
<option value="">-- no list --</option>
|
||||
{/if}
|
||||
</select>
|
||||
{:else if field_type == 'text'}
|
||||
<input
|
||||
bind:value={new_field_value}
|
||||
class="input ae_btn_surface min-w-64 w-96 max-w-full"
|
||||
/>
|
||||
{:else if field_type == 'textarea'}
|
||||
<textarea
|
||||
bind:value={new_field_value}
|
||||
cols={textarea_cols}
|
||||
rows={textarea_rows}
|
||||
class="textarea"
|
||||
></textarea>
|
||||
{:else}
|
||||
<input bind:value={new_field_value} class="input w-fit" />
|
||||
{/if}
|
||||
{#if allow_null}
|
||||
<button
|
||||
class="btn btn-sm ae_btn_warning m-1"
|
||||
onclick={() => {
|
||||
new_field_value = null;
|
||||
}}
|
||||
title="Set value to NULL"
|
||||
>
|
||||
Ø NULL
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<button
|
||||
class="
|
||||
<button
|
||||
class="
|
||||
ae_btn_warning_outlined
|
||||
btn btn-lg
|
||||
m-1
|
||||
"
|
||||
disabled={new_field_value === current_field_value}
|
||||
onclick={async () => {
|
||||
handle_obj_field_patch(new_field_value);
|
||||
}}
|
||||
title="Save new field value"
|
||||
>
|
||||
{#if new_field_value === current_field_value}
|
||||
{#if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
<!-- <span>{patch_result}</span> -->
|
||||
{:else if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-save mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
</button>
|
||||
disabled={new_field_value === current_field_value}
|
||||
onclick={async () => {
|
||||
handle_obj_field_patch(new_field_value);
|
||||
}}
|
||||
title="Save new field value"
|
||||
>
|
||||
{#if new_field_value === current_field_value}
|
||||
{#if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
<!-- <span>{patch_result}</span> -->
|
||||
{:else if btn_label}
|
||||
{@html btn_label}
|
||||
{:else}
|
||||
<span class="fas fa-save mx-1"></span>
|
||||
<span>Save</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<div class="field_patch_result" class:hidden={!patch_status}>
|
||||
{#await ae_promises.api_update__ae_obj}
|
||||
<span class="fas fa-spinner fa-spin mx-1"></span>
|
||||
<span>Processing...</span>
|
||||
{:then}
|
||||
{#if patch_status}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>{patch_status}</span>
|
||||
{:else}
|
||||
<!-- <div>Nothing to show yet...</div> -->
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
<div class="field_patch_result" class:hidden={!patch_status}>
|
||||
{#await ae_promises.api_update__ae_obj}
|
||||
<span class="fas fa-spinner fa-spin mx-1"></span>
|
||||
<span>Processing...</span>
|
||||
{:then}
|
||||
{#if patch_status}
|
||||
<span class="fas fa-check mx-1"></span>
|
||||
<span>{patch_status}</span>
|
||||
{:else}
|
||||
<!-- <div>Nothing to show yet...</div> -->
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.ae_crud.outline_element .field_viewing_wrapper {
|
||||
outline: dotted thin hsla(0, 50%, 50%, 0);
|
||||
transition: outline 3s 1s;
|
||||
}
|
||||
.ae_crud.outline_element .field_viewing_wrapper:hover {
|
||||
outline: dashed thin hsla(0, 50%, 50%, 0.9);
|
||||
transition: outline 1s 0.5s;
|
||||
}
|
||||
.ae_crud.outline_element .field_viewing_wrapper {
|
||||
outline: dotted thin hsla(0, 50%, 50%, 0);
|
||||
transition: outline 3s 1s;
|
||||
}
|
||||
.ae_crud.outline_element .field_viewing_wrapper:hover {
|
||||
outline: dashed thin hsla(0, 50%, 50%, 0.9);
|
||||
transition: outline 1s 0.5s;
|
||||
}
|
||||
|
||||
.ae_crud .field_viewing_wrapper {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
.ae_crud .field_viewing_wrapper {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
opacity: 0.25;
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
opacity: 0.25;
|
||||
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 1s; /* no delay */
|
||||
transition-duration: 0.55s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 1s; /* no delay */
|
||||
transition-duration: 0.55s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.ae_crud .field_viewing_wrapper:hover {
|
||||
/* outline: solid thin hsla(0,50%,50%,.9); */
|
||||
/* color: hsla(0,50%,50%,.9); */
|
||||
.ae_crud .field_viewing_wrapper:hover {
|
||||
/* outline: solid thin hsla(0,50%,50%,.9); */
|
||||
/* color: hsla(0,50%,50%,.9); */
|
||||
|
||||
opacity: 1;
|
||||
opacity: 1;
|
||||
|
||||
/* NOTE: transition when hover starts */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 0.25s; /* no delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
/* NOTE: transition when hover starts */
|
||||
transition-property: opacity, background-color, border-color, color, height, width;
|
||||
transition-delay: 0.25s; /* no delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
}
|
||||
|
||||
.ae_crud .field_editing_wrapper {
|
||||
/* outline: dashed thin pink; */
|
||||
.ae_crud .field_editing_wrapper {
|
||||
/* outline: dashed thin pink; */
|
||||
|
||||
/* position: relative; */
|
||||
/* position: relative; */
|
||||
|
||||
/* contain: layout; */
|
||||
/* contain: size; */
|
||||
/* contain: none; */
|
||||
contain: content;
|
||||
/* contain: layout; */
|
||||
/* contain: size; */
|
||||
/* contain: none; */
|
||||
contain: content;
|
||||
|
||||
box-shadow: 0.5em 0.5em 0.75em 0.75em hsla(0, 0%, 0%, 0.5);
|
||||
box-shadow: 0.5em 0.5em 0.75em 0.75em hsla(0, 0%, 0%, 0.5);
|
||||
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
/* background-color: hsla(0,0%,50%,.5); */
|
||||
/* border: dashed thin transparent; */
|
||||
/* color: hsla(0,0%,50%,.8); */
|
||||
/* background-color: hsla(0,0%,50%,.5); */
|
||||
/* border: dashed thin transparent; */
|
||||
|
||||
/* background-color: yellow; */
|
||||
background-color: hsla(60, 50%, 80%, 0.95);
|
||||
border: solid thin hsla(0, 50%, 50%, 0.5);
|
||||
border-radius: 0.5em;
|
||||
/* background-color: yellow; */
|
||||
background-color: hsla(60, 50%, 80%, 0.95);
|
||||
border: solid thin hsla(0, 50%, 50%, 0.5);
|
||||
border-radius: 0.5em;
|
||||
|
||||
height: auto;
|
||||
/* height: 100%; */
|
||||
max-height: 100%;
|
||||
height: auto;
|
||||
/* height: 100%; */
|
||||
max-height: 100%;
|
||||
|
||||
min-width: fit-content;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
min-width: fit-content;
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
|
||||
/* font-size: 1em; */
|
||||
/* line-height: 1em; */
|
||||
/* font-size: 1em; */
|
||||
/* line-height: 1em; */
|
||||
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: background-color, border-color, color, height, width;
|
||||
transition-delay: 0.75s; /* short delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
/* NOTE: transition when hover ends */
|
||||
transition-property: background-color, border-color, color, height, width;
|
||||
transition-delay: 0.75s; /* short delay */
|
||||
transition-duration: 0.5s;
|
||||
transition-timing-function: linear;
|
||||
|
||||
z-index: 1;
|
||||
z-index: 1;
|
||||
|
||||
padding: 0.5em;
|
||||
}
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper:hover {
|
||||
background-color: hsla(60, 60%, 90%, 0.8);
|
||||
z-index: 55;
|
||||
}
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper:hover {
|
||||
background-color: hsla(60, 60%, 90%, 0.8);
|
||||
z-index: 55;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper {
|
||||
/* display: block; */
|
||||
display: inline-block;
|
||||
/* display: inline; */
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper {
|
||||
/* display: block; */
|
||||
display: inline-block;
|
||||
/* display: inline; */
|
||||
|
||||
box-shadow: initial;
|
||||
background-color: hsla(60, 50%, 80%, 0.4);
|
||||
box-shadow: initial;
|
||||
background-color: hsla(60, 50%, 80%, 0.4);
|
||||
|
||||
padding: 0.25em;
|
||||
padding: 0.25em;
|
||||
|
||||
position: initial;
|
||||
position: initial;
|
||||
|
||||
z-index: 0;
|
||||
z-index: 0;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
|
||||
width: 30%;
|
||||
}
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper.display_block_edit {
|
||||
/* display: block; */
|
||||
.ae_crud.show_crud.display_inline .field_editing_wrapper.display_block_edit {
|
||||
/* display: block; */
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
|
||||
flex-grow: 1;
|
||||
flex-grow: 1;
|
||||
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
height: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ae_crud textarea {
|
||||
height: auto;
|
||||
}
|
||||
/* END: Svelte CRUD (update) component */
|
||||
.ae_crud textarea {
|
||||
height: auto;
|
||||
}
|
||||
/* END: Svelte CRUD (update) component */
|
||||
</style>
|
||||
|
||||
@@ -1,151 +1,157 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { ensureCodeMirrorModules } from './codemirror_modules';
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { ensureCodeMirrorModules } from './codemirror_modules';
|
||||
|
||||
export let content: string = '';
|
||||
export let placeholder: string = 'Start typing...';
|
||||
export let content: string = '';
|
||||
export let placeholder: string = 'Start typing...';
|
||||
|
||||
let editor_container: HTMLDivElement;
|
||||
let editor_view: any;
|
||||
let cm: any; // Declare cm at the top level
|
||||
let editor_container: HTMLDivElement;
|
||||
let editor_view: any;
|
||||
let cm: any; // Declare cm at the top level
|
||||
|
||||
async function createEditor() {
|
||||
if (!browser) return;
|
||||
cm = await ensureCodeMirrorModules(); // Assign to the top-level cm
|
||||
if (!cm) return;
|
||||
async function createEditor() {
|
||||
if (!browser) return;
|
||||
cm = await ensureCodeMirrorModules(); // Assign to the top-level cm
|
||||
if (!cm) return;
|
||||
|
||||
// If an existing instance exists (HMR / remount), destroy it first
|
||||
if (editor_view && typeof editor_view.destroy === 'function') {
|
||||
try {
|
||||
editor_view.destroy();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
editor_view = null;
|
||||
}
|
||||
// If an existing instance exists (HMR / remount), destroy it first
|
||||
if (editor_view && typeof editor_view.destroy === 'function') {
|
||||
try {
|
||||
editor_view.destroy();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
editor_view = null;
|
||||
}
|
||||
|
||||
// Build extensions defensively
|
||||
const extensions = [
|
||||
cm.lineNumbers(),
|
||||
cm.highlightSpecialChars(),
|
||||
cm.history(),
|
||||
cm.foldGutter(),
|
||||
cm.drawSelection(),
|
||||
cm.dropCursor(),
|
||||
cm.EditorState_allowMultipleSelections.of(true),
|
||||
cm.indentOnInput(),
|
||||
cm.bracketMatching(),
|
||||
cm.closeBrackets(),
|
||||
cm.autocompletion(),
|
||||
cm.rectangularSelection(),
|
||||
cm.crosshairCursor(),
|
||||
cm.highlightActiveLine(),
|
||||
cm.highlightActiveLineGutter(),
|
||||
cm.EditorView_lineWrapping,
|
||||
cm.keymap.of([
|
||||
...cm.defaultKeymap,
|
||||
...cm.searchKeymap,
|
||||
...cm.historyKeymap,
|
||||
...cm.foldKeymap,
|
||||
...cm.completionKeymap,
|
||||
...cm.lintKeymap
|
||||
]),
|
||||
cm.markdown ? cm.markdown({ base: cm.markdownLanguage }) : null,
|
||||
cm.EditorView && cm.EditorView.updateListener
|
||||
? cm.EditorView.updateListener.of((update: any) => {
|
||||
if (update.docChanged) content = update.state.doc.toString();
|
||||
})
|
||||
: null
|
||||
].filter(Boolean);
|
||||
// Build extensions defensively
|
||||
const extensions = [
|
||||
cm.lineNumbers(),
|
||||
cm.highlightSpecialChars(),
|
||||
cm.history(),
|
||||
cm.foldGutter(),
|
||||
cm.drawSelection(),
|
||||
cm.dropCursor(),
|
||||
cm.EditorState_allowMultipleSelections.of(true),
|
||||
cm.indentOnInput(),
|
||||
cm.bracketMatching(),
|
||||
cm.closeBrackets(),
|
||||
cm.autocompletion(),
|
||||
cm.rectangularSelection(),
|
||||
cm.crosshairCursor(),
|
||||
cm.highlightActiveLine(),
|
||||
cm.highlightActiveLineGutter(),
|
||||
cm.EditorView_lineWrapping,
|
||||
cm.keymap.of([
|
||||
...cm.defaultKeymap,
|
||||
...cm.searchKeymap,
|
||||
...cm.historyKeymap,
|
||||
...cm.foldKeymap,
|
||||
...cm.completionKeymap,
|
||||
...cm.lintKeymap
|
||||
]),
|
||||
cm.markdown ? cm.markdown({ base: cm.markdownLanguage }) : null,
|
||||
cm.EditorView && cm.EditorView.updateListener
|
||||
? cm.EditorView.updateListener.of((update: any) => {
|
||||
if (update.docChanged) content = update.state.doc.toString();
|
||||
})
|
||||
: null
|
||||
].filter(Boolean);
|
||||
|
||||
// Create editor
|
||||
editor_view = new cm.EditorView({
|
||||
state: cm.EditorState.create({
|
||||
doc: content ?? '',
|
||||
extensions
|
||||
}),
|
||||
parent: editor_container
|
||||
});
|
||||
}
|
||||
// Create editor
|
||||
editor_view = new cm.EditorView({
|
||||
state: cm.EditorState.create({
|
||||
doc: content ?? '',
|
||||
extensions
|
||||
}),
|
||||
parent: editor_container
|
||||
});
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
// ensure it's created only in browser and after modules resolved
|
||||
await createEditor();
|
||||
});
|
||||
onMount(async () => {
|
||||
// ensure it's created only in browser and after modules resolved
|
||||
await createEditor();
|
||||
});
|
||||
|
||||
onDestroy(() => {
|
||||
if (editor_view && typeof editor_view.destroy === 'function') {
|
||||
try {
|
||||
editor_view.destroy();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
editor_view = null;
|
||||
}
|
||||
});
|
||||
onDestroy(() => {
|
||||
if (editor_view && typeof editor_view.destroy === 'function') {
|
||||
try {
|
||||
editor_view.destroy();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
editor_view = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Helper functions using the live editor_view (unchanged)
|
||||
const wrapSelection = (before: string, after: string = before) => {
|
||||
if (!editor_view) return;
|
||||
const state = editor_view.state;
|
||||
const changes = state.changeByRange((range: any) => {
|
||||
const isAlreadyWrapped =
|
||||
state.sliceDoc(range.from - before.length, range.from) === before &&
|
||||
state.sliceDoc(range.to, range.to + after.length) === after;
|
||||
// Helper functions using the live editor_view (unchanged)
|
||||
const wrapSelection = (before: string, after: string = before) => {
|
||||
if (!editor_view) return;
|
||||
const state = editor_view.state;
|
||||
const changes = state.changeByRange((range: any) => {
|
||||
const isAlreadyWrapped =
|
||||
state.sliceDoc(range.from - before.length, range.from) === before &&
|
||||
state.sliceDoc(range.to, range.to + after.length) === after;
|
||||
|
||||
if (isAlreadyWrapped) {
|
||||
return {
|
||||
changes: [
|
||||
{ from: range.from - before.length, to: range.from, insert: '' },
|
||||
{ from: range.to, to: range.to + after.length, insert: '' }
|
||||
],
|
||||
range: cm.EditorSelection.range(range.from - before.length, range.to - before.length)
|
||||
};
|
||||
}
|
||||
if (isAlreadyWrapped) {
|
||||
return {
|
||||
changes: [
|
||||
{ from: range.from - before.length, to: range.from, insert: '' },
|
||||
{ from: range.to, to: range.to + after.length, insert: '' }
|
||||
],
|
||||
range: cm.EditorSelection.range(
|
||||
range.from - before.length,
|
||||
range.to - before.length
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
changes: [
|
||||
{ from: range.from, insert: before },
|
||||
{ from: range.to, insert: after }
|
||||
],
|
||||
range: cm.EditorSelection.range(range.from + before.length, range.to + before.length)
|
||||
};
|
||||
});
|
||||
editor_view.dispatch(changes);
|
||||
editor_view.focus();
|
||||
};
|
||||
return {
|
||||
changes: [
|
||||
{ from: range.from, insert: before },
|
||||
{ from: range.to, insert: after }
|
||||
],
|
||||
range: cm.EditorSelection.range(
|
||||
range.from + before.length,
|
||||
range.to + before.length
|
||||
)
|
||||
};
|
||||
});
|
||||
editor_view.dispatch(changes);
|
||||
editor_view.focus();
|
||||
};
|
||||
|
||||
const insertList = () => {
|
||||
if (!editor_view) return;
|
||||
const state = editor_view.state;
|
||||
const changes = state.changeByRange((range: any) => {
|
||||
const line = state.doc.lineAt(range.from);
|
||||
return {
|
||||
changes: [{ from: line.from, insert: '- ' }],
|
||||
range: cm.EditorSelection.range(range.from + 2, range.to + 2)
|
||||
};
|
||||
});
|
||||
editor_view.dispatch(changes);
|
||||
editor_view.focus();
|
||||
};
|
||||
const insertList = () => {
|
||||
if (!editor_view) return;
|
||||
const state = editor_view.state;
|
||||
const changes = state.changeByRange((range: any) => {
|
||||
const line = state.doc.lineAt(range.from);
|
||||
return {
|
||||
changes: [{ from: line.from, insert: '- ' }],
|
||||
range: cm.EditorSelection.range(range.from + 2, range.to + 2)
|
||||
};
|
||||
});
|
||||
editor_view.dispatch(changes);
|
||||
editor_view.focus();
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class="codemirror-wrapper border rounded">
|
||||
<div class="toolbar p-1 bg-gray-100 border-b">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => wrapSelection('**')}
|
||||
class="px-2 py-1 rounded hover:bg-gray-200"><b>B</b></button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => wrapSelection('*')}
|
||||
class="px-2 py-1 rounded hover:bg-gray-200"><i>I</i></button
|
||||
>
|
||||
<button type="button" on:click={insertList} class="px-2 py-1 rounded hover:bg-gray-200"
|
||||
>List</button
|
||||
>
|
||||
</div>
|
||||
<div bind:this={editor_container} class="h-full min-h-[150px] overflow-auto"></div>
|
||||
<div class="toolbar p-1 bg-gray-100 border-b">
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => wrapSelection('**')}
|
||||
class="px-2 py-1 rounded hover:bg-gray-200"><b>B</b></button
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
on:click={() => wrapSelection('*')}
|
||||
class="px-2 py-1 rounded hover:bg-gray-200"><i>I</i></button
|
||||
>
|
||||
<button type="button" on:click={insertList} class="px-2 py-1 rounded hover:bg-gray-200"
|
||||
>List</button
|
||||
>
|
||||
</div>
|
||||
<div bind:this={editor_container} class="h-full min-h-[150px] overflow-auto"></div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<script lang="ts">
|
||||
import ElementCodemirrorEditor from './element_codemirror_editor.svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import ElementCodemirrorEditor from './element_codemirror_editor.svelte';
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
export let html_text: string = '';
|
||||
export let placeholder: string = 'Type your text here...';
|
||||
export let classes: string = '';
|
||||
export let html_text: string = '';
|
||||
export let placeholder: string = 'Type your text here...';
|
||||
export let classes: string = '';
|
||||
</script>
|
||||
|
||||
<div class="block w-full h-full {classes}">
|
||||
{#if browser}
|
||||
<ElementCodemirrorEditor
|
||||
class="p-1 transition-all duration-1000"
|
||||
bind:content={html_text}
|
||||
{placeholder}
|
||||
/>
|
||||
{:else}
|
||||
<!-- server / prerender placeholder to avoid SSR loading CM -->
|
||||
<div class="p-2 text-sm text-surface-600-400">Editor (client only)</div>
|
||||
{/if}
|
||||
{#if browser}
|
||||
<ElementCodemirrorEditor
|
||||
class="p-1 transition-all duration-1000"
|
||||
bind:content={html_text}
|
||||
{placeholder}
|
||||
/>
|
||||
{:else}
|
||||
<!-- server / prerender placeholder to avoid SSR loading CM -->
|
||||
<div class="p-2 text-sm text-surface-600-400">Editor (client only)</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,426 +1,438 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount, tick } from 'svelte';
|
||||
import { createEventDispatcher, onMount, tick } from 'svelte';
|
||||
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
import { check_hosted_file_obj_w_hash } from '$lib/ae_core/core__check_hosted_file_obj_w_hash';
|
||||
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
import { check_hosted_file_obj_w_hash } from '$lib/ae_core/core__check_hosted_file_obj_w_hash';
|
||||
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
|
||||
export let element_id = 'svelte_input_file_element';
|
||||
export let input_name = 'file_list';
|
||||
export let container_class_li: string[] = [];
|
||||
export let input_class_li: string[] = ['file_drop_area'];
|
||||
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', '', 'text-sm'];
|
||||
export let element_id = 'svelte_input_file_element';
|
||||
export let input_name = 'file_list';
|
||||
export let container_class_li: string[] = [];
|
||||
export let input_class_li: string[] = ['file_drop_area'];
|
||||
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', '', 'text-sm'];
|
||||
|
||||
export let multiple: boolean = true;
|
||||
export let required: boolean = true;
|
||||
export let accept: string =
|
||||
'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
|
||||
export let untrusted_extension_list = ['bin', 'dmg', 'exe', 'js', 'msi', 'php', 'py', 'sh'];
|
||||
export let legacy_extension_list = ['avi', 'doc', 'ppt', 'xls', 'wmv'];
|
||||
export let use_selected_file_table = true;
|
||||
export let multiple: boolean = true;
|
||||
export let required: boolean = true;
|
||||
export let accept: string =
|
||||
'audio/*, image/*, video/*, .bak, .cfg, .css, .csv, .doc, .docx, .gz, .htm, .html, .ini, .iso, .j2, .json, .key, .keynote, .md, .pdf, .ppt, .pptx, .rar, .rtf, .sql, .svelte, ttf, .txt, .xls, .xlsx, .xz, .zip, .bin, .dmg, .exe, .js, .msi, .php, .py, .sh';
|
||||
export let untrusted_extension_list = ['bin', 'dmg', 'exe', 'js', 'msi', 'php', 'py', 'sh'];
|
||||
export let legacy_extension_list = ['avi', 'doc', 'ppt', 'xls', 'wmv'];
|
||||
export let use_selected_file_table = true;
|
||||
|
||||
export let file_list_status: null | string = null;
|
||||
export let processed_file_list: any[] = [];
|
||||
export let file_list_status: null | string = null;
|
||||
export let processed_file_list: any[] = [];
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let input_file_list: any = null;
|
||||
let input_file_list_processed: any[] = [];
|
||||
export let input_file_list: any = null;
|
||||
let input_file_list_processed: any[] = [];
|
||||
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element Input File');
|
||||
});
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element Input File');
|
||||
});
|
||||
|
||||
$: if (input_file_list) {
|
||||
console.log(input_file_list);
|
||||
$: if (input_file_list) {
|
||||
console.log(input_file_list);
|
||||
|
||||
process_file_list(input_file_list).then(function (result) {
|
||||
// console.log(result);
|
||||
process_file_list(input_file_list).then(function (result) {
|
||||
// console.log(result);
|
||||
|
||||
if (!result || !result.length) {
|
||||
file_list_status = 'none';
|
||||
}
|
||||
if (!result || !result.length) {
|
||||
file_list_status = 'none';
|
||||
}
|
||||
|
||||
// Save the results to the file upload list to be displayed as a table.
|
||||
input_file_list_processed = result; // Includes file hash
|
||||
// Save the results to the file upload list to be displayed as a table.
|
||||
input_file_list_processed = result; // Includes file hash
|
||||
|
||||
dispatch('input_file_list_updated', {
|
||||
element_id: element_id,
|
||||
input_file_list: input_file_list,
|
||||
input_file_list_processed: result // Includes file hash
|
||||
});
|
||||
});
|
||||
}
|
||||
dispatch('input_file_list_updated', {
|
||||
element_id: element_id,
|
||||
input_file_list: input_file_list,
|
||||
input_file_list_processed: result // Includes file hash
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function process_file_list(file_list) {
|
||||
console.log('*** process_file_list() ***');
|
||||
async function process_file_list(file_list) {
|
||||
console.log('*** process_file_list() ***');
|
||||
|
||||
file_list_status = 'processing';
|
||||
processed_file_list = [];
|
||||
file_list_status = 'processing';
|
||||
processed_file_list = [];
|
||||
|
||||
if (!file_list) {
|
||||
// file_list_processed = null;
|
||||
file_list_status = 'none';
|
||||
// await tick();
|
||||
return processed_file_list;
|
||||
}
|
||||
if (!file_list) {
|
||||
// file_list_processed = null;
|
||||
file_list_status = 'none';
|
||||
// await tick();
|
||||
return processed_file_list;
|
||||
}
|
||||
|
||||
// const forLoop = async _ => {
|
||||
// console.log('*** Start ***');
|
||||
// const forLoop = async _ => {
|
||||
// console.log('*** Start ***');
|
||||
|
||||
// for (let [i, file_item] of file_list.entries()) { // Not sure why this does not work???
|
||||
for await (const [i, file_item] of Array.prototype.entries.call(file_list)) {
|
||||
console.log(i, file_item);
|
||||
// for (let [i, file_item] of file_list.entries()) { // Not sure why this does not work???
|
||||
for await (const [i, file_item] of Array.prototype.entries.call(file_list)) {
|
||||
console.log(i, file_item);
|
||||
|
||||
// NOTE: The file list is readonly. The filenames can not be changed here.
|
||||
if (
|
||||
file_item.name.endsWith('.odpmac') ||
|
||||
file_item.name.endsWith('.odpwin') ||
|
||||
file_item.name.endsWith('.pptmac') ||
|
||||
file_item.name.endsWith('.pptwin') ||
|
||||
file_item.name.endsWith('.pptxmac') ||
|
||||
file_item.name.endsWith('.pptxwin')
|
||||
) {
|
||||
console.log('This file extension may need to be fixed? API upload will take care of it.');
|
||||
// file_item.name = file_item.name.replace('.odpwin', '.odp');
|
||||
}
|
||||
// NOTE: The file list is readonly. The filenames can not be changed here.
|
||||
if (
|
||||
file_item.name.endsWith('.odpmac') ||
|
||||
file_item.name.endsWith('.odpwin') ||
|
||||
file_item.name.endsWith('.pptmac') ||
|
||||
file_item.name.endsWith('.pptwin') ||
|
||||
file_item.name.endsWith('.pptxmac') ||
|
||||
file_item.name.endsWith('.pptxwin')
|
||||
) {
|
||||
console.log(
|
||||
'This file extension may need to be fixed? API upload will take care of it.'
|
||||
);
|
||||
// file_item.name = file_item.name.replace('.odpwin', '.odp');
|
||||
}
|
||||
|
||||
let file_data: key_val = {};
|
||||
let file_data: key_val = {};
|
||||
|
||||
let filename = file_item.name;
|
||||
// console.log(filename);
|
||||
file_data['filename'] = filename;
|
||||
let filename = file_item.name;
|
||||
// console.log(filename);
|
||||
file_data['filename'] = filename;
|
||||
|
||||
let guessed_extension = ae_util.guess_file_extension(filename);
|
||||
file_data['guessed_extension'] = guessed_extension;
|
||||
let guessed_extension = ae_util.guess_file_extension(filename);
|
||||
file_data['guessed_extension'] = guessed_extension;
|
||||
|
||||
file_data['type'] = file_item.type;
|
||||
file_data['type'] = file_item.type;
|
||||
|
||||
let modified_date = new Date(file_item.lastModified);
|
||||
file_data['modified_date'] = modified_date;
|
||||
let modified_datetime_string = ae_util.iso_datetime_formatter(
|
||||
modified_date,
|
||||
'datetime_medium'
|
||||
);
|
||||
file_data['modified_datetime_string'] = modified_datetime_string;
|
||||
let modified_date = new Date(file_item.lastModified);
|
||||
file_data['modified_date'] = modified_date;
|
||||
let modified_datetime_string = ae_util.iso_datetime_formatter(
|
||||
modified_date,
|
||||
'datetime_medium'
|
||||
);
|
||||
file_data['modified_datetime_string'] = modified_datetime_string;
|
||||
|
||||
let file_size_bytes = file_item.size;
|
||||
file_data['file_size_bytes'] = file_size_bytes;
|
||||
let file_size_string = ae_util.format_bytes(file_item.size, 2);
|
||||
file_data['file_size_string'] = file_size_string;
|
||||
let file_size_bytes = file_item.size;
|
||||
file_data['file_size_bytes'] = file_size_bytes;
|
||||
let file_size_string = ae_util.format_bytes(file_item.size, 2);
|
||||
file_data['file_size_string'] = file_size_string;
|
||||
|
||||
// // NOTE: Calculate the hash of the file before upload. Check if this exact file has already been uploaded.
|
||||
// let file_reader = new FileReader();
|
||||
// file_reader.onload = async function() {
|
||||
// // NOTE: Calculate the hash of the file before upload. Check if this exact file has already been uploaded.
|
||||
// let file_reader = new FileReader();
|
||||
// file_reader.onload = async function() {
|
||||
|
||||
// const hash_buffer = crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// let hash_hex_test = hash_buffer.then(async function (result_buffer) {
|
||||
// const hash_array = Array.from(new Uint8Array(result_buffer)); // convert buffer to byte array
|
||||
// const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// console.log(`File hash hex? ${hash_hex}`);
|
||||
// file_data['hash_sha256'] = hash_hex;
|
||||
// return hash_hex;
|
||||
// })
|
||||
// .catch(function (error: any) {
|
||||
// console.log('Something went wrong?', error);
|
||||
// });
|
||||
// const hash_buffer = crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// let hash_hex_test = hash_buffer.then(async function (result_buffer) {
|
||||
// const hash_array = Array.from(new Uint8Array(result_buffer)); // convert buffer to byte array
|
||||
// const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// console.log(`File hash hex? ${hash_hex}`);
|
||||
// file_data['hash_sha256'] = hash_hex;
|
||||
// return hash_hex;
|
||||
// })
|
||||
// .catch(function (error: any) {
|
||||
// console.log('Something went wrong?', error);
|
||||
// });
|
||||
|
||||
// return hash_hex_test;
|
||||
// return hash_hex_test;
|
||||
|
||||
// // file_data['hash_hex_test'] = hash_hex_test;
|
||||
// // file_data['hash_hex_test'] = hash_hex_test;
|
||||
|
||||
// // const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// // let hash_str = await new TextDecoder().decode(hash_buffer);
|
||||
// // console.log(`File hash string? ${hash_str}`);
|
||||
// // file_data['hash_str'] = hash_str;
|
||||
// // const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// // let hash_str = await new TextDecoder().decode(hash_buffer);
|
||||
// // console.log(`File hash string? ${hash_str}`);
|
||||
// // file_data['hash_str'] = hash_str;
|
||||
|
||||
// // const hash_array = Array.from(new Uint8Array(hash_buffer)); // convert buffer to byte array
|
||||
// // const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// // console.log(`File hash hex? ${hash_hex}`);
|
||||
// // const hash_array = Array.from(new Uint8Array(hash_buffer)); // convert buffer to byte array
|
||||
// // const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// // console.log(`File hash hex? ${hash_hex}`);
|
||||
|
||||
// // file_data['hash_sha256'] = hash_hex;
|
||||
// // return hash_hex_test;
|
||||
// // return hash_hex;
|
||||
// }
|
||||
// // file_data['hash_sha256'] = hash_hex;
|
||||
// // return hash_hex_test;
|
||||
// // return hash_hex;
|
||||
// }
|
||||
|
||||
// // file_reader.then(function (result) {
|
||||
// // console.log(`File hash hex? ${result}`);
|
||||
// // return hash_hex;
|
||||
// // })
|
||||
// // .catch(function (error: any) {
|
||||
// // console.log('No results returned or failed.', error);
|
||||
// // });
|
||||
// // file_data['hash_sha256'] = file_reader.readAsArrayBuffer(file_item);
|
||||
// // file_reader.then(function (result) {
|
||||
// // console.log(`File hash hex? ${result}`);
|
||||
// // return hash_hex;
|
||||
// // })
|
||||
// // .catch(function (error: any) {
|
||||
// // console.log('No results returned or failed.', error);
|
||||
// // });
|
||||
// // file_data['hash_sha256'] = file_reader.readAsArrayBuffer(file_item);
|
||||
|
||||
let warning_untrusted_extension = false;
|
||||
let warning_legacy_extension = false;
|
||||
let warning_size = false;
|
||||
let warning_message = null;
|
||||
let warning_untrusted_extension = false;
|
||||
let warning_legacy_extension = false;
|
||||
let warning_size = false;
|
||||
let warning_message = null;
|
||||
|
||||
if (untrusted_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is an untrusted extension. Going to warn.');
|
||||
warning_untrusted_extension = true;
|
||||
warning_message =
|
||||
'It appears this an untrusted file type and is likely meant to be an executable or installable application. It is <strong>strongly</strong> recommended that this file not be used.';
|
||||
} else if (legacy_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is a legacy extension. Going to warn.');
|
||||
warning_legacy_extension = true;
|
||||
if (guessed_extension == 'ppt') {
|
||||
warning_message =
|
||||
'It appears this is a legacy PowerPoint file and has not been officially supported since Office PowerPoint 2003. This file is known to have issues and may not work well. It is <strong>strongly</strong> recommended that this file be saved using the modern PPTX format.';
|
||||
} else if (guessed_extension == 'avi') {
|
||||
warning_message =
|
||||
'It appears this is a video file using the AVI format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG. The file will also likely be much smaller.';
|
||||
} else if (guessed_extension == 'wmv') {
|
||||
warning_message =
|
||||
"It appears this is a video file using Microsoft's WMV format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG.";
|
||||
} else {
|
||||
warning_message =
|
||||
'It appears this is a legacy or not very well supported file format. It is <strong>strongly</strong> recommended that it be saved in an alternative format if possible.';
|
||||
}
|
||||
} else if (file_size_bytes > 52428800) {
|
||||
// 50 MB = 52428800 bytes
|
||||
// 100 MB = 104857600 bytes
|
||||
console.log(
|
||||
`This is a large file size ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes). Going to warn.`
|
||||
);
|
||||
warning_size = true;
|
||||
if (file_size_bytes > 2147483648) {
|
||||
// > 2 GB
|
||||
warning_message = `This file size (${file_size_string}) is very large and will take at <strong>least</strong> a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Most audio, image, and video files can be compressed without a significant loss in quality. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly.`;
|
||||
} else if (file_size_bytes > 209715200) {
|
||||
// > 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take at <strong>least</strong> a few minutes to upload depending on your network connection. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else if (file_size_bytes > 104857600) {
|
||||
// 100 MB to 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take a few minutes to upload depending on your network connection. Be sure you have a stable network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else {
|
||||
// 50 to 100 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and may take a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (untrusted_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is an untrusted extension. Going to warn.');
|
||||
warning_untrusted_extension = true;
|
||||
warning_message =
|
||||
'It appears this an untrusted file type and is likely meant to be an executable or installable application. It is <strong>strongly</strong> recommended that this file not be used.';
|
||||
} else if (legacy_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is a legacy extension. Going to warn.');
|
||||
warning_legacy_extension = true;
|
||||
if (guessed_extension == 'ppt') {
|
||||
warning_message =
|
||||
'It appears this is a legacy PowerPoint file and has not been officially supported since Office PowerPoint 2003. This file is known to have issues and may not work well. It is <strong>strongly</strong> recommended that this file be saved using the modern PPTX format.';
|
||||
} else if (guessed_extension == 'avi') {
|
||||
warning_message =
|
||||
'It appears this is a video file using the AVI format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG. The file will also likely be much smaller.';
|
||||
} else if (guessed_extension == 'wmv') {
|
||||
warning_message =
|
||||
"It appears this is a video file using Microsoft's WMV format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG.";
|
||||
} else {
|
||||
warning_message =
|
||||
'It appears this is a legacy or not very well supported file format. It is <strong>strongly</strong> recommended that it be saved in an alternative format if possible.';
|
||||
}
|
||||
} else if (file_size_bytes > 52428800) {
|
||||
// 50 MB = 52428800 bytes
|
||||
// 100 MB = 104857600 bytes
|
||||
console.log(
|
||||
`This is a large file size ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes). Going to warn.`
|
||||
);
|
||||
warning_size = true;
|
||||
if (file_size_bytes > 2147483648) {
|
||||
// > 2 GB
|
||||
warning_message = `This file size (${file_size_string}) is very large and will take at <strong>least</strong> a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Most audio, image, and video files can be compressed without a significant loss in quality. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly.`;
|
||||
} else if (file_size_bytes > 209715200) {
|
||||
// > 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take at <strong>least</strong> a few minutes to upload depending on your network connection. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else if (file_size_bytes > 104857600) {
|
||||
// 100 MB to 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take a few minutes to upload depending on your network connection. Be sure you have a stable network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else {
|
||||
// 50 to 100 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and may take a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
file_data['warning_untrusted_extension'] = warning_untrusted_extension;
|
||||
file_data['warning_legacy_extension'] = warning_legacy_extension;
|
||||
file_data['warning_size'] = warning_size;
|
||||
file_data['warning_untrusted_extension'] = warning_untrusted_extension;
|
||||
file_data['warning_legacy_extension'] = warning_legacy_extension;
|
||||
file_data['warning_size'] = warning_size;
|
||||
|
||||
file_data['warning_message'] = warning_message;
|
||||
file_data['warning_message'] = warning_message;
|
||||
|
||||
file_data['uploaded'] = null;
|
||||
file_data['uploaded_bytes'] = null;
|
||||
file_data['uploaded'] = null;
|
||||
file_data['uploaded_bytes'] = null;
|
||||
|
||||
// input_file_list_processed.push(JSON.parse(JSON.stringify(file_data)));
|
||||
// input_file_list_processed = input_file_list_processed;
|
||||
// input_file_list_processed.push(JSON.parse(JSON.stringify(file_data)));
|
||||
// input_file_list_processed = input_file_list_processed;
|
||||
|
||||
// console.log(get_file_hash(file_item));
|
||||
// console.log(await get_file_hash(file_item));
|
||||
// console.log(get_file_hash(file_item));
|
||||
// console.log(await get_file_hash(file_item));
|
||||
|
||||
let file_hash = null;
|
||||
let file_hash = null;
|
||||
|
||||
// Only hash files less than 2 GB (2147483648 bytes)!!!
|
||||
console.log(`File size: ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes)`);
|
||||
if (file_size_bytes < 2000000000) {
|
||||
// > 2 GB 2 147 483 648
|
||||
file_hash = await ae_util.get_file_hash(file_item);
|
||||
} else {
|
||||
// File size in MB
|
||||
console.log(`File is too large to hash. File size: ${file_size_bytes / 1048576} MB`);
|
||||
}
|
||||
// Only hash files less than 2 GB (2147483648 bytes)!!!
|
||||
console.log(`File size: ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes)`);
|
||||
if (file_size_bytes < 2000000000) {
|
||||
// > 2 GB 2 147 483 648
|
||||
file_hash = await ae_util.get_file_hash(file_item);
|
||||
} else {
|
||||
// File size in MB
|
||||
console.log(
|
||||
`File is too large to hash. File size: ${file_size_bytes / 1048576} MB`
|
||||
);
|
||||
}
|
||||
|
||||
if (file_hash) {
|
||||
console.log(`Found file hash to lookup: ${ae_util.shorten_string({ string: file_hash })}`);
|
||||
file_data['hash_sha256'] = file_hash;
|
||||
if (file_hash) {
|
||||
console.log(
|
||||
`Found file hash to lookup: ${ae_util.shorten_string({ string: file_hash })}`
|
||||
);
|
||||
file_data['hash_sha256'] = file_hash;
|
||||
|
||||
let check_hosted_file_obj_w_hash_result = await check_hosted_file_obj_w_hash({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_hash: file_hash
|
||||
});
|
||||
let check_hosted_file_obj_w_hash_result = await check_hosted_file_obj_w_hash({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_hash: file_hash
|
||||
});
|
||||
|
||||
// console.log(check_hosted_file_obj_w_hash_result);
|
||||
// console.log(check_hosted_file_obj_w_hash_result);
|
||||
|
||||
if (
|
||||
check_hosted_file_obj_w_hash_result &&
|
||||
check_hosted_file_obj_w_hash_result.hosted_file_found_check
|
||||
) {
|
||||
console.log('Matching hash!!!');
|
||||
file_data['hash_sha256_match'] = true;
|
||||
// $ae_events.pres_mgmt.new_upload_list[i].hash_sha256_match = true;
|
||||
// $ae_events = $ae_events;
|
||||
}
|
||||
} else {
|
||||
file_data['hash_sha256'] = null;
|
||||
file_data['hash_sha256_match'] = false;
|
||||
}
|
||||
if (
|
||||
check_hosted_file_obj_w_hash_result &&
|
||||
check_hosted_file_obj_w_hash_result.hosted_file_found_check
|
||||
) {
|
||||
console.log('Matching hash!!!');
|
||||
file_data['hash_sha256_match'] = true;
|
||||
// $ae_events.pres_mgmt.new_upload_list[i].hash_sha256_match = true;
|
||||
// $ae_events = $ae_events;
|
||||
}
|
||||
} else {
|
||||
file_data['hash_sha256'] = null;
|
||||
file_data['hash_sha256_match'] = false;
|
||||
}
|
||||
|
||||
processed_file_list.push(file_data);
|
||||
// input_file_list_processed.push(file_data);
|
||||
}
|
||||
processed_file_list.push(file_data);
|
||||
// input_file_list_processed.push(file_data);
|
||||
}
|
||||
|
||||
file_list_status = 'ready';
|
||||
console.log(processed_file_list);
|
||||
file_list_status = 'ready';
|
||||
console.log(processed_file_list);
|
||||
|
||||
// return JSON.parse(JSON.stringify(processed_file_list));
|
||||
return processed_file_list;
|
||||
}
|
||||
// return JSON.parse(JSON.stringify(processed_file_list));
|
||||
return processed_file_list;
|
||||
}
|
||||
|
||||
function remove_file_from_filelist(index) {
|
||||
console.log('*** remove_file_from_filelist() ***');
|
||||
function remove_file_from_filelist(index) {
|
||||
console.log('*** remove_file_from_filelist() ***');
|
||||
|
||||
// Can not use something like this because it is readonly:
|
||||
const dt = new DataTransfer();
|
||||
// let input = document.getElementById(input_element_id);
|
||||
// Can not use something like this because it is readonly:
|
||||
const dt = new DataTransfer();
|
||||
// let input = document.getElementById(input_element_id);
|
||||
|
||||
let input_element = document.querySelector('input[type="file"].svelte_input_file_element');
|
||||
let input_element = document.querySelector('input[type="file"].svelte_input_file_element');
|
||||
|
||||
if (!input_element) {
|
||||
console.error('Could not find the input element.');
|
||||
return false;
|
||||
}
|
||||
if (!input_element) {
|
||||
console.error('Could not find the input element.');
|
||||
return false;
|
||||
}
|
||||
|
||||
let files = input_file_list;
|
||||
let files = input_file_list;
|
||||
|
||||
if (!files || !files.length) {
|
||||
console.error('No files found in the file list.');
|
||||
file_list_status = null;
|
||||
return false;
|
||||
}
|
||||
if (!files || !files.length) {
|
||||
console.error('No files found in the file list.');
|
||||
file_list_status = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (index !== i)
|
||||
// Only include the file if it does not match the index value.
|
||||
dt.items.add(file);
|
||||
}
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (index !== i)
|
||||
// Only include the file if it does not match the index value.
|
||||
dt.items.add(file);
|
||||
}
|
||||
|
||||
// NOTE: I thought just setting the input_element.files OR input_file_list would trigger the input_file_list change.
|
||||
// input_element.files = Object.assign({}, dt.files);
|
||||
input_element.files = dt.files; // Assign the updates list
|
||||
// input_file_list = null;
|
||||
input_file_list = dt.files; // I feel like this should not need to be done, but doing it anyways.
|
||||
// NOTE: I thought just setting the input_element.files OR input_file_list would trigger the input_file_list change.
|
||||
// input_element.files = Object.assign({}, dt.files);
|
||||
input_element.files = dt.files; // Assign the updates list
|
||||
// input_file_list = null;
|
||||
input_file_list = dt.files; // I feel like this should not need to be done, but doing it anyways.
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="svelte_element ae_element ae_input_file flex flex-col gap-1 items-center justify-center {container_class_li.join(
|
||||
' '
|
||||
)} text-center"
|
||||
class="svelte_element ae_element ae_input_file flex flex-col gap-1 items-center justify-center {container_class_li.join(
|
||||
' '
|
||||
)} text-center"
|
||||
>
|
||||
<label for={element_id} class="svelte_input_file_label text-center">
|
||||
<div>
|
||||
<span class="fas fa-upload"></span>
|
||||
<!-- Select files to upload -->
|
||||
<!-- <span class="fas fa-file-archive"></span> -->
|
||||
<strong>Upload your files</strong>
|
||||
<!-- (drag and drop) -->
|
||||
</div>
|
||||
<span>
|
||||
Presentation related files only<br />
|
||||
(PowerPoint, Keynote, PDF, mp4, Word Doc, Excel, txt, etc)
|
||||
</span>
|
||||
</label>
|
||||
<label for={element_id} class="svelte_input_file_label text-center">
|
||||
<div>
|
||||
<span class="fas fa-upload"></span>
|
||||
<!-- Select files to upload -->
|
||||
<!-- <span class="fas fa-file-archive"></span> -->
|
||||
<strong>Upload your files</strong>
|
||||
<!-- (drag and drop) -->
|
||||
</div>
|
||||
<span>
|
||||
Presentation related files only<br />
|
||||
(PowerPoint, Keynote, PDF, mp4, Word Doc, Excel, txt, etc)
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<input
|
||||
id={element_id}
|
||||
type="file"
|
||||
bind:files={input_file_list}
|
||||
{multiple}
|
||||
{required}
|
||||
{accept}
|
||||
name={input_name}
|
||||
class="svelte_input_file_element {input_class_li.join(' ')}"
|
||||
/>
|
||||
<input
|
||||
id={element_id}
|
||||
type="file"
|
||||
bind:files={input_file_list}
|
||||
{multiple}
|
||||
{required}
|
||||
{accept}
|
||||
name={input_name}
|
||||
class="svelte_input_file_element {input_class_li.join(' ')}"
|
||||
/>
|
||||
|
||||
{#if file_list_status == 'processing'}
|
||||
<div class="file_list_status ae_warning preset-tonal-warning border border-warning-500 p-1 m-1">
|
||||
<span class="fas fa-spinner fa-spin m-1"></span> Processing selected file list...
|
||||
</div>
|
||||
{/if}
|
||||
{#if file_list_status == 'processing'}
|
||||
<div
|
||||
class="file_list_status ae_warning preset-tonal-warning border border-warning-500 p-1 m-1"
|
||||
>
|
||||
<span class="fas fa-spinner fa-spin m-1"></span> Processing selected file list...
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- {#await input_file_list_processed} -->
|
||||
<!-- {:then} -->
|
||||
{#if use_selected_file_table && input_file_list_processed && input_file_list_processed.length}
|
||||
<strong>Files selected for upload</strong>
|
||||
<table class="slct_file_list text-sm {table_class_li.join(' ')}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Remove</th>
|
||||
<th>Filename</th>
|
||||
<th>Modified</th>
|
||||
<th>Size</th>
|
||||
<!-- <th>Type</th> -->
|
||||
<th>Ext</th>
|
||||
<th>Hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{#each input_file_list_processed as file_list_item, file_index}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="file_remove">
|
||||
<button
|
||||
on:click|preventDefault={() => {
|
||||
remove_file_from_filelist(file_index);
|
||||
}}
|
||||
class="btn btn-md preset-tonal-warning hover:preset-filled-secondary-500 m-1"
|
||||
title="Remove file from upload list"
|
||||
>
|
||||
<span class="fas fa-minus"></span>
|
||||
<span class="hidden">Remove</span>
|
||||
</button>
|
||||
</td>
|
||||
<td class="file_filename">{file_list_item.filename}</td>
|
||||
<td class="file_last_modified">{file_list_item.modified_datetime_string}</td>
|
||||
<td class="file_size" class:bg-pink-200={file_list_item.warning_size}>
|
||||
{file_list_item.file_size_string}
|
||||
<!-- {#if $ae_sess.api_upload_kv[link_to_id]}
|
||||
<!-- {#await input_file_list_processed} -->
|
||||
<!-- {:then} -->
|
||||
{#if use_selected_file_table && input_file_list_processed && input_file_list_processed.length}
|
||||
<strong>Files selected for upload</strong>
|
||||
<table class="slct_file_list text-sm {table_class_li.join(' ')}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Remove</th>
|
||||
<th>Filename</th>
|
||||
<th>Modified</th>
|
||||
<th>Size</th>
|
||||
<!-- <th>Type</th> -->
|
||||
<th>Ext</th>
|
||||
<th>Hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{#each input_file_list_processed as file_list_item, file_index}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="file_remove">
|
||||
<button
|
||||
on:click|preventDefault={() => {
|
||||
remove_file_from_filelist(file_index);
|
||||
}}
|
||||
class="btn btn-md preset-tonal-warning hover:preset-filled-secondary-500 m-1"
|
||||
title="Remove file from upload list"
|
||||
>
|
||||
<span class="fas fa-minus"></span>
|
||||
<span class="hidden">Remove</span>
|
||||
</button>
|
||||
</td>
|
||||
<td class="file_filename">{file_list_item.filename}</td>
|
||||
<td class="file_last_modified">{file_list_item.modified_datetime_string}</td
|
||||
>
|
||||
<td class="file_size" class:bg-pink-200={file_list_item.warning_size}>
|
||||
{file_list_item.file_size_string}
|
||||
<!-- {#if $ae_sess.api_upload_kv[link_to_id]}
|
||||
<span class="text-xs">({$ae_sess.api_upload_kv[link_to_id].percent_completed}%)</span>
|
||||
{/if} -->
|
||||
</td>
|
||||
<!-- <td class="file_type" class:warning_file_untrusted_extension={file_list_item.warning_untrusted_extension} class:warning_file_legacy_extension={file_list_item.warning_legacy_extension}>{file_list_item.type}</td> -->
|
||||
<td
|
||||
class="file_extension"
|
||||
class:bg-red-200={file_list_item.warning_untrusted_extension}
|
||||
class:bg-pink-200={file_list_item.warning_legacy_extension}
|
||||
>
|
||||
{file_list_item.guessed_extension}
|
||||
</td>
|
||||
<td class="file_hash file_hash256" class:bg-pink-200={file_list_item.hash_sha256_match}>
|
||||
{ae_util.shorten_string({
|
||||
string: file_list_item.hash_sha256,
|
||||
begin_length: 5,
|
||||
end_length: 4,
|
||||
wildcard_length: 2
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{/each}
|
||||
</table>
|
||||
{/if}
|
||||
</td>
|
||||
<!-- <td class="file_type" class:warning_file_untrusted_extension={file_list_item.warning_untrusted_extension} class:warning_file_legacy_extension={file_list_item.warning_legacy_extension}>{file_list_item.type}</td> -->
|
||||
<td
|
||||
class="file_extension"
|
||||
class:bg-red-200={file_list_item.warning_untrusted_extension}
|
||||
class:bg-pink-200={file_list_item.warning_legacy_extension}
|
||||
>
|
||||
{file_list_item.guessed_extension}
|
||||
</td>
|
||||
<td
|
||||
class="file_hash file_hash256"
|
||||
class:bg-pink-200={file_list_item.hash_sha256_match}
|
||||
>
|
||||
{ae_util.shorten_string({
|
||||
string: file_list_item.hash_sha256,
|
||||
begin_length: 5,
|
||||
end_length: 4,
|
||||
wildcard_length: 2
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{/each}
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
th {
|
||||
text-align: center;
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
.file_last_modified {
|
||||
font-size: smaller;
|
||||
}
|
||||
th {
|
||||
text-align: center;
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
.file_last_modified {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.file_size,
|
||||
.file_type {
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
.file_size,
|
||||
.file_type {
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
|
||||
.file_hash {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
.file_hash {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,406 +1,419 @@
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher, onMount, tick } from 'svelte';
|
||||
import { createEventDispatcher, onMount, tick } from 'svelte';
|
||||
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
import { check_hosted_file_obj_w_hash } from '$lib/ae_core/core__check_hosted_file_obj_w_hash';
|
||||
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
import { check_hosted_file_obj_w_hash } from '$lib/ae_core/core__check_hosted_file_obj_w_hash';
|
||||
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
|
||||
// export let element_id = 'svelte_input_file_element';
|
||||
export let container_class_li: string[] = [];
|
||||
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', '', 'text-sm'];
|
||||
// export let element_id = 'svelte_input_file_element';
|
||||
export let container_class_li: string[] = [];
|
||||
export let table_class_li: string[] = ['table', 'table-sm', 'table-striped', '', 'text-sm'];
|
||||
|
||||
export let untrusted_extension_list = ['bin', 'dmg', 'exe', 'js', 'msi', 'php', 'py', 'sh'];
|
||||
export let legacy_extension_list = ['avi', 'doc', 'ppt', 'xls', 'wmv'];
|
||||
export let use_selected_file_table = true;
|
||||
export let untrusted_extension_list = ['bin', 'dmg', 'exe', 'js', 'msi', 'php', 'py', 'sh'];
|
||||
export let legacy_extension_list = ['avi', 'doc', 'ppt', 'xls', 'wmv'];
|
||||
export let use_selected_file_table = true;
|
||||
|
||||
export let input_file_list: any = null;
|
||||
export let file_list_status: null | string = null;
|
||||
export let processed_file_list: any[] = [];
|
||||
export let input_file_list: any = null;
|
||||
export let file_list_status: null | string = null;
|
||||
export let processed_file_list: any[] = [];
|
||||
|
||||
// const dispatch = createEventDispatcher();
|
||||
// const dispatch = createEventDispatcher();
|
||||
|
||||
// let input_file_list_processed: any[] = [];
|
||||
// let input_file_list_processed: any[] = [];
|
||||
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element Input File');
|
||||
});
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element Input File');
|
||||
});
|
||||
|
||||
$: if (input_file_list) {
|
||||
console.log(input_file_list);
|
||||
$: if (input_file_list) {
|
||||
console.log(input_file_list);
|
||||
|
||||
process_file_list(input_file_list).then(function (result) {
|
||||
// console.log(result);
|
||||
process_file_list(input_file_list).then(function (result) {
|
||||
// console.log(result);
|
||||
|
||||
if (!result || !result.length) {
|
||||
processed_file_list = [];
|
||||
file_list_status = 'none';
|
||||
}
|
||||
if (!result || !result.length) {
|
||||
processed_file_list = [];
|
||||
file_list_status = 'none';
|
||||
}
|
||||
|
||||
// Save the results to the file upload list to be displayed as a table.
|
||||
// input_file_list_processed = result; // Includes file hash
|
||||
// Save the results to the file upload list to be displayed as a table.
|
||||
// input_file_list_processed = result; // Includes file hash
|
||||
|
||||
// dispatch(
|
||||
// 'input_file_list_updated',
|
||||
// {
|
||||
// element_id: element_id,
|
||||
// input_file_list: input_file_list,
|
||||
// input_file_list_processed: result, // Includes file hash
|
||||
// }
|
||||
// );
|
||||
});
|
||||
} else {
|
||||
processed_file_list = [];
|
||||
file_list_status = 'none';
|
||||
}
|
||||
// dispatch(
|
||||
// 'input_file_list_updated',
|
||||
// {
|
||||
// element_id: element_id,
|
||||
// input_file_list: input_file_list,
|
||||
// input_file_list_processed: result, // Includes file hash
|
||||
// }
|
||||
// );
|
||||
});
|
||||
} else {
|
||||
processed_file_list = [];
|
||||
file_list_status = 'none';
|
||||
}
|
||||
|
||||
async function process_file_list(file_list) {
|
||||
console.log('*** process_file_list() ***');
|
||||
async function process_file_list(file_list) {
|
||||
console.log('*** process_file_list() ***');
|
||||
|
||||
file_list_status = 'processing';
|
||||
processed_file_list = [];
|
||||
file_list_status = 'processing';
|
||||
processed_file_list = [];
|
||||
|
||||
if (!file_list) {
|
||||
// file_list_processed = null;
|
||||
file_list_status = 'none';
|
||||
// await tick();
|
||||
return processed_file_list;
|
||||
}
|
||||
if (!file_list) {
|
||||
// file_list_processed = null;
|
||||
file_list_status = 'none';
|
||||
// await tick();
|
||||
return processed_file_list;
|
||||
}
|
||||
|
||||
// const forLoop = async _ => {
|
||||
// console.log('*** Start ***');
|
||||
// const forLoop = async _ => {
|
||||
// console.log('*** Start ***');
|
||||
|
||||
// for (let [i, file_item] of file_list.entries()) { // Not sure why this does not work???
|
||||
for await (const [i, file_item] of Array.prototype.entries.call(file_list)) {
|
||||
console.log(i, file_item);
|
||||
// for (let [i, file_item] of file_list.entries()) { // Not sure why this does not work???
|
||||
for await (const [i, file_item] of Array.prototype.entries.call(file_list)) {
|
||||
console.log(i, file_item);
|
||||
|
||||
// NOTE: The file list is readonly. The filenames can not be changed here.
|
||||
if (
|
||||
file_item.name.endsWith('.odpmac') ||
|
||||
file_item.name.endsWith('.odpwin') ||
|
||||
file_item.name.endsWith('.pptmac') ||
|
||||
file_item.name.endsWith('.pptwin') ||
|
||||
file_item.name.endsWith('.pptxmac') ||
|
||||
file_item.name.endsWith('.pptxwin')
|
||||
) {
|
||||
console.log('This file extension may need to be fixed? API upload will take care of it.');
|
||||
// file_item.name = file_item.name.replace('.odpwin', '.odp');
|
||||
}
|
||||
// NOTE: The file list is readonly. The filenames can not be changed here.
|
||||
if (
|
||||
file_item.name.endsWith('.odpmac') ||
|
||||
file_item.name.endsWith('.odpwin') ||
|
||||
file_item.name.endsWith('.pptmac') ||
|
||||
file_item.name.endsWith('.pptwin') ||
|
||||
file_item.name.endsWith('.pptxmac') ||
|
||||
file_item.name.endsWith('.pptxwin')
|
||||
) {
|
||||
console.log(
|
||||
'This file extension may need to be fixed? API upload will take care of it.'
|
||||
);
|
||||
// file_item.name = file_item.name.replace('.odpwin', '.odp');
|
||||
}
|
||||
|
||||
let file_data: key_val = {};
|
||||
let file_data: key_val = {};
|
||||
|
||||
let filename = file_item.name;
|
||||
// console.log(filename);
|
||||
file_data['filename'] = filename;
|
||||
let filename = file_item.name;
|
||||
// console.log(filename);
|
||||
file_data['filename'] = filename;
|
||||
|
||||
let guessed_extension = ae_util.guess_file_extension(filename);
|
||||
file_data['guessed_extension'] = guessed_extension;
|
||||
let guessed_extension = ae_util.guess_file_extension(filename);
|
||||
file_data['guessed_extension'] = guessed_extension;
|
||||
|
||||
file_data['type'] = file_item.type;
|
||||
file_data['type'] = file_item.type;
|
||||
|
||||
let modified_date = new Date(file_item.lastModified);
|
||||
file_data['modified_date'] = modified_date;
|
||||
let modified_datetime_string = ae_util.iso_datetime_formatter(
|
||||
modified_date,
|
||||
'datetime_medium'
|
||||
);
|
||||
file_data['modified_datetime_string'] = modified_datetime_string;
|
||||
let modified_date = new Date(file_item.lastModified);
|
||||
file_data['modified_date'] = modified_date;
|
||||
let modified_datetime_string = ae_util.iso_datetime_formatter(
|
||||
modified_date,
|
||||
'datetime_medium'
|
||||
);
|
||||
file_data['modified_datetime_string'] = modified_datetime_string;
|
||||
|
||||
let file_size_bytes = file_item.size;
|
||||
file_data['file_size_bytes'] = file_size_bytes;
|
||||
let file_size_string = ae_util.format_bytes(file_item.size, 2);
|
||||
file_data['file_size_string'] = file_size_string;
|
||||
let file_size_bytes = file_item.size;
|
||||
file_data['file_size_bytes'] = file_size_bytes;
|
||||
let file_size_string = ae_util.format_bytes(file_item.size, 2);
|
||||
file_data['file_size_string'] = file_size_string;
|
||||
|
||||
// // NOTE: Calculate the hash of the file before upload. Check if this exact file has already been uploaded.
|
||||
// let file_reader = new FileReader();
|
||||
// file_reader.onload = async function() {
|
||||
// // NOTE: Calculate the hash of the file before upload. Check if this exact file has already been uploaded.
|
||||
// let file_reader = new FileReader();
|
||||
// file_reader.onload = async function() {
|
||||
|
||||
// const hash_buffer = crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// let hash_hex_test = hash_buffer.then(async function (result_buffer) {
|
||||
// const hash_array = Array.from(new Uint8Array(result_buffer)); // convert buffer to byte array
|
||||
// const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// console.log(`File hash hex? ${hash_hex}`);
|
||||
// file_data['hash_sha256'] = hash_hex;
|
||||
// return hash_hex;
|
||||
// })
|
||||
// .catch(function (error: any) {
|
||||
// console.log('Something went wrong?', error);
|
||||
// });
|
||||
// const hash_buffer = crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// let hash_hex_test = hash_buffer.then(async function (result_buffer) {
|
||||
// const hash_array = Array.from(new Uint8Array(result_buffer)); // convert buffer to byte array
|
||||
// const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// console.log(`File hash hex? ${hash_hex}`);
|
||||
// file_data['hash_sha256'] = hash_hex;
|
||||
// return hash_hex;
|
||||
// })
|
||||
// .catch(function (error: any) {
|
||||
// console.log('Something went wrong?', error);
|
||||
// });
|
||||
|
||||
// return hash_hex_test;
|
||||
// return hash_hex_test;
|
||||
|
||||
// // file_data['hash_hex_test'] = hash_hex_test;
|
||||
// // file_data['hash_hex_test'] = hash_hex_test;
|
||||
|
||||
// // const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// // let hash_str = await new TextDecoder().decode(hash_buffer);
|
||||
// // console.log(`File hash string? ${hash_str}`);
|
||||
// // file_data['hash_str'] = hash_str;
|
||||
// // const hash_buffer = await crypto.subtle.digest('SHA-256', file_reader.result);
|
||||
// // let hash_str = await new TextDecoder().decode(hash_buffer);
|
||||
// // console.log(`File hash string? ${hash_str}`);
|
||||
// // file_data['hash_str'] = hash_str;
|
||||
|
||||
// // const hash_array = Array.from(new Uint8Array(hash_buffer)); // convert buffer to byte array
|
||||
// // const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// // console.log(`File hash hex? ${hash_hex}`);
|
||||
// // const hash_array = Array.from(new Uint8Array(hash_buffer)); // convert buffer to byte array
|
||||
// // const hash_hex = hash_array.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
// // console.log(`File hash hex? ${hash_hex}`);
|
||||
|
||||
// // file_data['hash_sha256'] = hash_hex;
|
||||
// // return hash_hex_test;
|
||||
// // return hash_hex;
|
||||
// }
|
||||
// // file_data['hash_sha256'] = hash_hex;
|
||||
// // return hash_hex_test;
|
||||
// // return hash_hex;
|
||||
// }
|
||||
|
||||
// // file_reader.then(function (result) {
|
||||
// // console.log(`File hash hex? ${result}`);
|
||||
// // return hash_hex;
|
||||
// // })
|
||||
// // .catch(function (error: any) {
|
||||
// // console.log('No results returned or failed.', error);
|
||||
// // });
|
||||
// // file_data['hash_sha256'] = file_reader.readAsArrayBuffer(file_item);
|
||||
// // file_reader.then(function (result) {
|
||||
// // console.log(`File hash hex? ${result}`);
|
||||
// // return hash_hex;
|
||||
// // })
|
||||
// // .catch(function (error: any) {
|
||||
// // console.log('No results returned or failed.', error);
|
||||
// // });
|
||||
// // file_data['hash_sha256'] = file_reader.readAsArrayBuffer(file_item);
|
||||
|
||||
let warning_untrusted_extension = false;
|
||||
let warning_legacy_extension = false;
|
||||
let warning_size = false;
|
||||
let warning_message = null;
|
||||
let warning_untrusted_extension = false;
|
||||
let warning_legacy_extension = false;
|
||||
let warning_size = false;
|
||||
let warning_message = null;
|
||||
|
||||
if (untrusted_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is an untrusted extension. Going to warn.');
|
||||
warning_untrusted_extension = true;
|
||||
warning_message =
|
||||
'It appears this an untrusted file type and is likely meant to be an executable or installable application. It is <strong>strongly</strong> recommended that this file not be used.';
|
||||
} else if (legacy_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is a legacy extension. Going to warn.');
|
||||
warning_legacy_extension = true;
|
||||
if (guessed_extension == 'ppt') {
|
||||
warning_message =
|
||||
'It appears this is a legacy PowerPoint file and has not been officially supported since Office PowerPoint 2003. This file is known to have issues and may not work well. It is <strong>strongly</strong> recommended that this file be saved using the modern PPTX format.';
|
||||
} else if (guessed_extension == 'avi') {
|
||||
warning_message =
|
||||
'It appears this is a video file using the AVI format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG. The file will also likely be much smaller.';
|
||||
} else if (guessed_extension == 'wmv') {
|
||||
warning_message =
|
||||
"It appears this is a video file using Microsoft's WMV format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG.";
|
||||
} else {
|
||||
warning_message =
|
||||
'It appears this is a legacy or not very well supported file format. It is <strong>strongly</strong> recommended that it be saved in an alternative format if possible.';
|
||||
}
|
||||
} else if (file_size_bytes > 52428800) {
|
||||
// 50 MB = 52428800 bytes
|
||||
// 100 MB = 104857600 bytes
|
||||
console.log(
|
||||
`This is a large file size ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes). Going to warn.`
|
||||
);
|
||||
warning_size = true;
|
||||
if (file_size_bytes > 2147483648) {
|
||||
// > 2 GB
|
||||
warning_message = `This file size (${file_size_string}) is very large and will take at <strong>least</strong> a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Most audio, image, and video files can be compressed without a significant loss in quality. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly.`;
|
||||
} else if (file_size_bytes > 209715200) {
|
||||
// > 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take at <strong>least</strong> a few minutes to upload depending on your network connection. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else if (file_size_bytes > 104857600) {
|
||||
// 100 MB to 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take a few minutes to upload depending on your network connection. Be sure you have a stable network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else {
|
||||
// 50 to 100 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and may take a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (untrusted_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is an untrusted extension. Going to warn.');
|
||||
warning_untrusted_extension = true;
|
||||
warning_message =
|
||||
'It appears this an untrusted file type and is likely meant to be an executable or installable application. It is <strong>strongly</strong> recommended that this file not be used.';
|
||||
} else if (legacy_extension_list.includes(guessed_extension)) {
|
||||
console.log('This is a legacy extension. Going to warn.');
|
||||
warning_legacy_extension = true;
|
||||
if (guessed_extension == 'ppt') {
|
||||
warning_message =
|
||||
'It appears this is a legacy PowerPoint file and has not been officially supported since Office PowerPoint 2003. This file is known to have issues and may not work well. It is <strong>strongly</strong> recommended that this file be saved using the modern PPTX format.';
|
||||
} else if (guessed_extension == 'avi') {
|
||||
warning_message =
|
||||
'It appears this is a video file using the AVI format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG. The file will also likely be much smaller.';
|
||||
} else if (guessed_extension == 'wmv') {
|
||||
warning_message =
|
||||
"It appears this is a video file using Microsoft's WMV format. It is <strong>strongly</strong> recommended that this file be re-saved as an MP4, MOV, MKV, or MPG/MPEG.";
|
||||
} else {
|
||||
warning_message =
|
||||
'It appears this is a legacy or not very well supported file format. It is <strong>strongly</strong> recommended that it be saved in an alternative format if possible.';
|
||||
}
|
||||
} else if (file_size_bytes > 52428800) {
|
||||
// 50 MB = 52428800 bytes
|
||||
// 100 MB = 104857600 bytes
|
||||
console.log(
|
||||
`This is a large file size ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes). Going to warn.`
|
||||
);
|
||||
warning_size = true;
|
||||
if (file_size_bytes > 2147483648) {
|
||||
// > 2 GB
|
||||
warning_message = `This file size (${file_size_string}) is very large and will take at <strong>least</strong> a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Most audio, image, and video files can be compressed without a significant loss in quality. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly.`;
|
||||
} else if (file_size_bytes > 209715200) {
|
||||
// > 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take at <strong>least</strong> a few minutes to upload depending on your network connection. Be sure you have a stable network connection, especially if you are uploading over a wireless connection. Many business (convention centers, hotels, restaurants, etc) cap upload speeds significantly. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else if (file_size_bytes > 104857600) {
|
||||
// 100 MB to 200 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and will likely take a few minutes to upload depending on your network connection. Be sure you have a stable network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
} else {
|
||||
// 50 to 100 MB
|
||||
warning_message = `This file size (${file_size_string}) is large and may take a few minutes to upload depending on your network connection. In some cases it may be worth compressing the file or embedded media. Many audio, image, and video files can be compressed without a significant loss in quality.`;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
file_data['warning_untrusted_extension'] = warning_untrusted_extension;
|
||||
file_data['warning_legacy_extension'] = warning_legacy_extension;
|
||||
file_data['warning_size'] = warning_size;
|
||||
file_data['warning_untrusted_extension'] = warning_untrusted_extension;
|
||||
file_data['warning_legacy_extension'] = warning_legacy_extension;
|
||||
file_data['warning_size'] = warning_size;
|
||||
|
||||
file_data['warning_message'] = warning_message;
|
||||
file_data['warning_message'] = warning_message;
|
||||
|
||||
file_data['uploaded'] = null;
|
||||
file_data['uploaded_bytes'] = null;
|
||||
file_data['uploaded'] = null;
|
||||
file_data['uploaded_bytes'] = null;
|
||||
|
||||
// input_file_list_processed.push(JSON.parse(JSON.stringify(file_data)));
|
||||
// input_file_list_processed = input_file_list_processed;
|
||||
// input_file_list_processed.push(JSON.parse(JSON.stringify(file_data)));
|
||||
// input_file_list_processed = input_file_list_processed;
|
||||
|
||||
// console.log(get_file_hash(file_item));
|
||||
// console.log(await get_file_hash(file_item));
|
||||
// console.log(get_file_hash(file_item));
|
||||
// console.log(await get_file_hash(file_item));
|
||||
|
||||
let file_hash = null;
|
||||
let file_hash = null;
|
||||
|
||||
// Only hash files less than 2 GB (2147483648 bytes)!!!
|
||||
console.log(`File size: ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes)`);
|
||||
if (file_size_bytes < 2000000000) {
|
||||
// > 2 GB 2 147 483 648
|
||||
file_hash = await ae_util.get_file_hash(file_item);
|
||||
} else {
|
||||
// File size in MB
|
||||
console.log(`File is too large to hash. File size: ${file_size_bytes / 1048576} MB`);
|
||||
}
|
||||
// Only hash files less than 2 GB (2147483648 bytes)!!!
|
||||
console.log(`File size: ${file_size_bytes / 1048576} MB (${file_size_bytes} bytes)`);
|
||||
if (file_size_bytes < 2000000000) {
|
||||
// > 2 GB 2 147 483 648
|
||||
file_hash = await ae_util.get_file_hash(file_item);
|
||||
} else {
|
||||
// File size in MB
|
||||
console.log(
|
||||
`File is too large to hash. File size: ${file_size_bytes / 1048576} MB`
|
||||
);
|
||||
}
|
||||
|
||||
if (file_hash) {
|
||||
console.log(`Found file hash to lookup: ${ae_util.shorten_string({ string: file_hash })}`);
|
||||
file_data['hash_sha256'] = file_hash;
|
||||
if (file_hash) {
|
||||
console.log(
|
||||
`Found file hash to lookup: ${ae_util.shorten_string({ string: file_hash })}`
|
||||
);
|
||||
file_data['hash_sha256'] = file_hash;
|
||||
|
||||
let check_hosted_file_obj_w_hash_result = await check_hosted_file_obj_w_hash({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_hash: file_hash
|
||||
});
|
||||
let check_hosted_file_obj_w_hash_result = await check_hosted_file_obj_w_hash({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_hash: file_hash
|
||||
});
|
||||
|
||||
// console.log(check_hosted_file_obj_w_hash_result);
|
||||
// console.log(check_hosted_file_obj_w_hash_result);
|
||||
|
||||
if (
|
||||
check_hosted_file_obj_w_hash_result &&
|
||||
check_hosted_file_obj_w_hash_result.hosted_file_found_check
|
||||
) {
|
||||
console.log('Matching hash!!!');
|
||||
file_data['hash_sha256_match'] = true;
|
||||
// $ae_events.pres_mgmt.new_upload_list[i].hash_sha256_match = true;
|
||||
// $ae_events = $ae_events;
|
||||
}
|
||||
} else {
|
||||
file_data['hash_sha256'] = null;
|
||||
file_data['hash_sha256_match'] = false;
|
||||
}
|
||||
if (
|
||||
check_hosted_file_obj_w_hash_result &&
|
||||
check_hosted_file_obj_w_hash_result.hosted_file_found_check
|
||||
) {
|
||||
console.log('Matching hash!!!');
|
||||
file_data['hash_sha256_match'] = true;
|
||||
// $ae_events.pres_mgmt.new_upload_list[i].hash_sha256_match = true;
|
||||
// $ae_events = $ae_events;
|
||||
}
|
||||
} else {
|
||||
file_data['hash_sha256'] = null;
|
||||
file_data['hash_sha256_match'] = false;
|
||||
}
|
||||
|
||||
processed_file_list.push(file_data);
|
||||
// input_file_list_processed.push(file_data);
|
||||
}
|
||||
processed_file_list.push(file_data);
|
||||
// input_file_list_processed.push(file_data);
|
||||
}
|
||||
|
||||
file_list_status = 'ready';
|
||||
console.log(processed_file_list);
|
||||
file_list_status = 'ready';
|
||||
console.log(processed_file_list);
|
||||
|
||||
// return JSON.parse(JSON.stringify(processed_file_list));
|
||||
return processed_file_list;
|
||||
}
|
||||
// return JSON.parse(JSON.stringify(processed_file_list));
|
||||
return processed_file_list;
|
||||
}
|
||||
|
||||
function remove_file_from_filelist(index) {
|
||||
console.log('*** remove_file_from_filelist() ***');
|
||||
function remove_file_from_filelist(index) {
|
||||
console.log('*** remove_file_from_filelist() ***');
|
||||
|
||||
// Can not use something like this because it is readonly:
|
||||
const dt = new DataTransfer();
|
||||
// let input = document.getElementById(input_element_id);
|
||||
// Can not use something like this because it is readonly:
|
||||
const dt = new DataTransfer();
|
||||
// let input = document.getElementById(input_element_id);
|
||||
|
||||
let input_element = document.querySelector('input[type="file"].svelte_input_file_element');
|
||||
let input_element = document.querySelector('input[type="file"].svelte_input_file_element');
|
||||
|
||||
if (!input_element) {
|
||||
console.error('Could not find the input element.');
|
||||
return false;
|
||||
}
|
||||
if (!input_element) {
|
||||
console.error('Could not find the input element.');
|
||||
return false;
|
||||
}
|
||||
|
||||
let files = input_file_list;
|
||||
let files = input_file_list;
|
||||
|
||||
if (!files || !files.length) {
|
||||
console.error('No files found in the file list.');
|
||||
file_list_status = null;
|
||||
return false;
|
||||
}
|
||||
if (!files || !files.length) {
|
||||
console.error('No files found in the file list.');
|
||||
file_list_status = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (index !== i)
|
||||
// Only include the file if it does not match the index value.
|
||||
dt.items.add(file);
|
||||
}
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
if (index !== i)
|
||||
// Only include the file if it does not match the index value.
|
||||
dt.items.add(file);
|
||||
}
|
||||
|
||||
// NOTE: I thought just setting the input_element.files OR input_file_list would trigger the input_file_list change.
|
||||
// input_element.files = Object.assign({}, dt.files);
|
||||
input_element.files = dt.files; // Assign the updates list
|
||||
// input_file_list = null;
|
||||
input_file_list = dt.files; // I feel like this should not need to be done, but doing it anyways.
|
||||
// NOTE: I thought just setting the input_element.files OR input_file_list would trigger the input_file_list change.
|
||||
// input_element.files = Object.assign({}, dt.files);
|
||||
input_element.files = dt.files; // Assign the updates list
|
||||
// input_file_list = null;
|
||||
input_file_list = dt.files; // I feel like this should not need to be done, but doing it anyways.
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="svelte_element ae_element ae_input_file flex flex-col gap-1 items-center justify-center {container_class_li.join(
|
||||
' '
|
||||
)} text-center"
|
||||
class="svelte_element ae_element ae_input_file flex flex-col gap-1 items-center justify-center {container_class_li.join(
|
||||
' '
|
||||
)} text-center"
|
||||
>
|
||||
{#if file_list_status == 'processing'}
|
||||
<div class="file_list_status ae_warning preset-tonal-warning border border-warning-500 p-1 m-1">
|
||||
<span class="fas fa-spinner fa-spin m-1"></span> Processing selected file list...
|
||||
</div>
|
||||
{/if}
|
||||
{#if file_list_status == 'processing'}
|
||||
<div
|
||||
class="file_list_status ae_warning preset-tonal-warning border border-warning-500 p-1 m-1"
|
||||
>
|
||||
<span class="fas fa-spinner fa-spin m-1"></span> Processing selected file list...
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- {#await processed_file_list} -->
|
||||
<!-- {:then} -->
|
||||
{#if use_selected_file_table && processed_file_list && processed_file_list.length}
|
||||
<strong>Files selected for upload</strong>
|
||||
<table class="slct_file_list text-sm {table_class_li.join(' ')}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Remove</th>
|
||||
<th>Filename</th>
|
||||
<th>Modified</th>
|
||||
<th>Size</th>
|
||||
<!-- <th>Type</th> -->
|
||||
<th>Ext</th>
|
||||
<th>Hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{#each processed_file_list as file_list_item, file_index}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="file_remove">
|
||||
<button
|
||||
on:click|preventDefault={() => {
|
||||
remove_file_from_filelist(file_index);
|
||||
}}
|
||||
class="btn btn-md preset-tonal-warning hover:preset-filled-secondary-500 m-1"
|
||||
title="Remove file from upload list"
|
||||
>
|
||||
<span class="fas fa-minus"></span>
|
||||
<span class="hidden">Remove</span>
|
||||
</button>
|
||||
</td>
|
||||
<td class="file_filename text-wrap break-all md:break-words">
|
||||
{file_list_item.filename}
|
||||
</td>
|
||||
<td class="file_last_modified">{file_list_item.modified_datetime_string}</td>
|
||||
<td class="file_size" class:bg-pink-200={file_list_item.warning_size}>
|
||||
{file_list_item.file_size_string}
|
||||
{#if $ae_sess.api_upload_kv[file_list_item.hash_sha256]}
|
||||
<span class="text-xs"
|
||||
>({$ae_sess.api_upload_kv[file_list_item.hash_sha256].percent_completed}%)</span
|
||||
>
|
||||
{/if}
|
||||
</td>
|
||||
<!-- <td class="file_type" class:warning_file_untrusted_extension={file_list_item.warning_untrusted_extension} class:warning_file_legacy_extension={file_list_item.warning_legacy_extension}>{file_list_item.type}</td> -->
|
||||
<td
|
||||
class="file_extension"
|
||||
class:bg-red-200={file_list_item.warning_untrusted_extension}
|
||||
class:bg-pink-200={file_list_item.warning_legacy_extension}
|
||||
>
|
||||
{file_list_item.guessed_extension}
|
||||
</td>
|
||||
<td class="file_hash file_hash256" class:bg-pink-200={file_list_item.hash_sha256_match}>
|
||||
{ae_util.shorten_string({
|
||||
string: file_list_item.hash_sha256,
|
||||
begin_length: 5,
|
||||
end_length: 4,
|
||||
wildcard_length: 2
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{/each}
|
||||
</table>
|
||||
{/if}
|
||||
<!-- {#await processed_file_list} -->
|
||||
<!-- {:then} -->
|
||||
{#if use_selected_file_table && processed_file_list && processed_file_list.length}
|
||||
<strong>Files selected for upload</strong>
|
||||
<table class="slct_file_list text-sm {table_class_li.join(' ')}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Remove</th>
|
||||
<th>Filename</th>
|
||||
<th>Modified</th>
|
||||
<th>Size</th>
|
||||
<!-- <th>Type</th> -->
|
||||
<th>Ext</th>
|
||||
<th>Hash</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{#each processed_file_list as file_list_item, file_index}
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="file_remove">
|
||||
<button
|
||||
on:click|preventDefault={() => {
|
||||
remove_file_from_filelist(file_index);
|
||||
}}
|
||||
class="btn btn-md preset-tonal-warning hover:preset-filled-secondary-500 m-1"
|
||||
title="Remove file from upload list"
|
||||
>
|
||||
<span class="fas fa-minus"></span>
|
||||
<span class="hidden">Remove</span>
|
||||
</button>
|
||||
</td>
|
||||
<td class="file_filename text-wrap break-all md:break-words">
|
||||
{file_list_item.filename}
|
||||
</td>
|
||||
<td class="file_last_modified">{file_list_item.modified_datetime_string}</td
|
||||
>
|
||||
<td class="file_size" class:bg-pink-200={file_list_item.warning_size}>
|
||||
{file_list_item.file_size_string}
|
||||
{#if $ae_sess.api_upload_kv[file_list_item.hash_sha256]}
|
||||
<span class="text-xs"
|
||||
>({$ae_sess.api_upload_kv[file_list_item.hash_sha256]
|
||||
.percent_completed}%)</span
|
||||
>
|
||||
{/if}
|
||||
</td>
|
||||
<!-- <td class="file_type" class:warning_file_untrusted_extension={file_list_item.warning_untrusted_extension} class:warning_file_legacy_extension={file_list_item.warning_legacy_extension}>{file_list_item.type}</td> -->
|
||||
<td
|
||||
class="file_extension"
|
||||
class:bg-red-200={file_list_item.warning_untrusted_extension}
|
||||
class:bg-pink-200={file_list_item.warning_legacy_extension}
|
||||
>
|
||||
{file_list_item.guessed_extension}
|
||||
</td>
|
||||
<td
|
||||
class="file_hash file_hash256"
|
||||
class:bg-pink-200={file_list_item.hash_sha256_match}
|
||||
>
|
||||
{ae_util.shorten_string({
|
||||
string: file_list_item.hash_sha256,
|
||||
begin_length: 5,
|
||||
end_length: 4,
|
||||
wildcard_length: 2
|
||||
})}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
{/each}
|
||||
</table>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
th {
|
||||
text-align: center;
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
.file_last_modified {
|
||||
font-size: smaller;
|
||||
}
|
||||
th {
|
||||
text-align: center;
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
.file_last_modified {
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
.file_size,
|
||||
.file_type {
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
.file_size,
|
||||
.file_type {
|
||||
/* font-size: smaller; */
|
||||
}
|
||||
|
||||
.file_hash {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
.file_hash {
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,70 +1,70 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
// import { events_func } from '$lib/ae_events_functions';
|
||||
container_class_li?: string | Array<string>;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
allow_basic?: boolean;
|
||||
allow_moderator?: boolean;
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
}
|
||||
interface Props {
|
||||
// import { events_func } from '$lib/ae_events_functions';
|
||||
container_class_li?: string | Array<string>;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
allow_basic?: boolean;
|
||||
allow_moderator?: boolean;
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
}
|
||||
|
||||
let {
|
||||
container_class_li = [],
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
allow_basic = false,
|
||||
allow_moderator = false,
|
||||
display_mode = 'default'
|
||||
}: Props = $props();
|
||||
let {
|
||||
container_class_li = [],
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
allow_basic = false,
|
||||
allow_moderator = false,
|
||||
display_mode = 'default'
|
||||
}: Props = $props();
|
||||
|
||||
import { liveQuery } from 'dexie';
|
||||
import { liveQuery } from 'dexie';
|
||||
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import Element_manage_event_file_li from '$lib/elements/element_manage_event_file_li.svelte';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import Element_manage_event_file_li from '$lib/elements/element_manage_event_file_li.svelte';
|
||||
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/stores/ae_events_stores';
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/stores/ae_events_stores';
|
||||
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
|
||||
// let ae_placeholder_li: key_val = {};
|
||||
// let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = {};
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = false;
|
||||
// let ae_triggers: key_val = {};
|
||||
// let ae_placeholder_li: key_val = {};
|
||||
// let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = {};
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = false;
|
||||
// let ae_triggers: key_val = {};
|
||||
|
||||
let dq__where_val: string = `${link_to_type}_id_random`;
|
||||
let dq__where_eq_val: string = link_to_id;
|
||||
let dq__where_val: string = `${link_to_type}_id_random`;
|
||||
let dq__where_eq_val: string = link_to_id;
|
||||
|
||||
// This should include all files that are associated with an object (event, location, session, presenter, etc.)
|
||||
// I am not sure why, but doing reverse() and then sortBy() seems to sort in descending order.
|
||||
let lq__event_file_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
let results = await db_events.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.reverse()
|
||||
.sortBy('created_on');
|
||||
// .toArray()
|
||||
return results;
|
||||
})
|
||||
);
|
||||
// This should include all files that are associated with an object (event, location, session, presenter, etc.)
|
||||
// I am not sure why, but doing reverse() and then sortBy() seems to sort in descending order.
|
||||
let lq__event_file_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
let results = await db_events.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.reverse()
|
||||
.sortBy('created_on');
|
||||
// .toArray()
|
||||
return results;
|
||||
})
|
||||
);
|
||||
</script>
|
||||
|
||||
<Element_manage_event_file_li
|
||||
{link_to_type}
|
||||
{link_to_id}
|
||||
{lq__event_file_obj_li}
|
||||
{allow_basic}
|
||||
{allow_moderator}
|
||||
{container_class_li}
|
||||
{display_mode}
|
||||
{link_to_type}
|
||||
{link_to_id}
|
||||
{lq__event_file_obj_li}
|
||||
{allow_basic}
|
||||
{allow_moderator}
|
||||
{container_class_li}
|
||||
{display_mode}
|
||||
/>
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
<script lang="ts">
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// import { events_func } from '$lib/ae_events_functions';
|
||||
container_class_li?: string | Array<string>;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
allow_basic?: boolean;
|
||||
allow_moderator?: boolean;
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
// import { events_func } from '$lib/ae_events_functions';
|
||||
container_class_li?: string | Array<string>;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
allow_basic?: boolean;
|
||||
allow_moderator?: boolean;
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
container_class_li = [],
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
allow_basic = false,
|
||||
allow_moderator = false,
|
||||
display_mode = 'default'
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = 0,
|
||||
container_class_li = [],
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
allow_basic = false,
|
||||
allow_moderator = false,
|
||||
display_mode = 'default'
|
||||
}: Props = $props();
|
||||
|
||||
import { liveQuery } from 'dexie';
|
||||
import { liveQuery } from 'dexie';
|
||||
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import Element_manage_event_file_li from '$lib/elements/element_manage_event_file_li.svelte';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import Element_manage_event_file_li from '$lib/elements/element_manage_event_file_li.svelte';
|
||||
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/stores/ae_events_stores';
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { db_events } from '$lib/ae_events/db_events';
|
||||
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/stores/ae_events_stores';
|
||||
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
|
||||
// let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = {};
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = false;
|
||||
// let ae_triggers: key_val = {};
|
||||
// let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = {};
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = false;
|
||||
// let ae_triggers: key_val = {};
|
||||
|
||||
let dq__where_val: string = `for_type`;
|
||||
let dq__where_eq_val: string = link_to_type;
|
||||
let dq__where_for_id_eq_val: string = link_to_id;
|
||||
let dq__where_val: string = `for_type`;
|
||||
let dq__where_eq_val: string = link_to_type;
|
||||
let dq__where_for_id_eq_val: string = link_to_id;
|
||||
|
||||
// This should only include files that are directly linked to an object (event, location, session, presenter, etc.).
|
||||
// I am not sure why, but doing reverse() and then sortBy() seems to sort in descending order.
|
||||
let lq__event_file_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
let results = await db_events.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((file) => file.for_id == dq__where_for_id_eq_val)
|
||||
.reverse()
|
||||
.sortBy('created_on');
|
||||
// .toArray()
|
||||
return results;
|
||||
})
|
||||
);
|
||||
// This should only include files that are directly linked to an object (event, location, session, presenter, etc.).
|
||||
// I am not sure why, but doing reverse() and then sortBy() seems to sort in descending order.
|
||||
let lq__event_file_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
let results = await db_events.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((file) => file.for_id == dq__where_for_id_eq_val)
|
||||
.reverse()
|
||||
.sortBy('created_on');
|
||||
// .toArray()
|
||||
return results;
|
||||
})
|
||||
);
|
||||
</script>
|
||||
|
||||
{#await lq__event_file_obj_li}
|
||||
<p>Loading...</p>
|
||||
<p>Loading...</p>
|
||||
{:then lq__event_file_obj_li}
|
||||
<Element_manage_event_file_li
|
||||
{link_to_type}
|
||||
{link_to_id}
|
||||
{lq__event_file_obj_li}
|
||||
{allow_basic}
|
||||
{allow_moderator}
|
||||
{container_class_li}
|
||||
{display_mode}
|
||||
{log_lvl}
|
||||
/>
|
||||
<Element_manage_event_file_li
|
||||
{link_to_type}
|
||||
{link_to_id}
|
||||
{lq__event_file_obj_li}
|
||||
{allow_basic}
|
||||
{allow_moderator}
|
||||
{container_class_li}
|
||||
{display_mode}
|
||||
{log_lvl}
|
||||
/>
|
||||
{:catch error}
|
||||
<p style="color: red;">{error.message}</p>
|
||||
<p style="color: red;">{error.message}</p>
|
||||
{/await}
|
||||
|
||||
@@ -1,244 +1,264 @@
|
||||
<script lang="ts">
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/stores/ae_stores';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
import { core_func } from '$lib/ae_core/ae_core_functions';
|
||||
|
||||
// export let allow_basic: boolean = false;
|
||||
// export let allow_basic: boolean = false;
|
||||
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
lq__hosted_file_obj_li: any;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
// export let allow_moderator: boolean = false;
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
max_file_count?: number;
|
||||
file_type?: string; // 'image', 'video', 'audio', 'document', 'other'
|
||||
slct_hosted_file_kv?: key_val;
|
||||
slct_hosted_file_id?: any;
|
||||
slct_hosted_file_obj?: any;
|
||||
}
|
||||
interface Props {
|
||||
log_lvl?: number;
|
||||
class_li_default?: string;
|
||||
class_li?: string;
|
||||
lq__hosted_file_obj_li: any;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
// export let allow_moderator: boolean = false;
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
max_file_count?: number;
|
||||
file_type?: string; // 'image', 'video', 'audio', 'document', 'other'
|
||||
slct_hosted_file_kv?: key_val;
|
||||
slct_hosted_file_id?: any;
|
||||
slct_hosted_file_obj?: any;
|
||||
}
|
||||
|
||||
let {
|
||||
log_lvl = 0,
|
||||
class_li_default = 'flex flex-col gap-1 items-center justify-center w-fit max-w-4xl mx-auto my-1 max-h-96 overflow-auto',
|
||||
class_li = '',
|
||||
lq__hosted_file_obj_li = $bindable([]),
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
display_mode = 'default',
|
||||
max_file_count = 49,
|
||||
file_type = 'all',
|
||||
slct_hosted_file_kv = $bindable({}),
|
||||
slct_hosted_file_id = $bindable(null),
|
||||
slct_hosted_file_obj = $bindable(null)
|
||||
}: Props = $props();
|
||||
let {
|
||||
log_lvl = 0,
|
||||
class_li_default = 'flex flex-col gap-1 items-center justify-center w-fit max-w-4xl mx-auto my-1 max-h-96 overflow-auto',
|
||||
class_li = '',
|
||||
lq__hosted_file_obj_li = $bindable([]),
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
display_mode = 'default',
|
||||
max_file_count = 49,
|
||||
file_type = 'all',
|
||||
slct_hosted_file_kv = $bindable({}),
|
||||
slct_hosted_file_id = $bindable(null),
|
||||
slct_hosted_file_obj = $bindable(null)
|
||||
}: Props = $props();
|
||||
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
|
||||
// let ae_placeholder_li: key_val = {};
|
||||
let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = $state({});
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = $ae_loc.core?.show__direct_download ?? false;
|
||||
// let ae_triggers: key_val = {};
|
||||
// let ae_placeholder_li: key_val = {};
|
||||
let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = $state({});
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = $ae_loc.core?.show__direct_download ?? false;
|
||||
// let ae_triggers: key_val = {};
|
||||
</script>
|
||||
|
||||
<section class="{class_li_default} {class_li}">
|
||||
<h3 class="h3" class:hidden={!$lq__hosted_file_obj_li?.length || display_mode != 'default'}>
|
||||
Manage Files:
|
||||
<span
|
||||
class="font-bold bg-success-100 px-4 border rounded-lg border-success-200"
|
||||
title="Files for {link_to_type ?? '-- not set --'}: {link_to_id ??
|
||||
'-- not set --'} (files: {$lq__hosted_file_obj_li?.length ?? 'None'})"
|
||||
>
|
||||
<span class="fas fa-folder-open mx-1"></span>
|
||||
{@html $lq__hosted_file_obj_li ? `${$lq__hosted_file_obj_li.length}×` : '-- none --'}
|
||||
</span>
|
||||
</h3>
|
||||
<h3 class="h3" class:hidden={!$lq__hosted_file_obj_li?.length || display_mode != 'default'}>
|
||||
Manage Files:
|
||||
<span
|
||||
class="font-bold bg-success-100 px-4 border rounded-lg border-success-200"
|
||||
title="Files for {link_to_type ?? '-- not set --'}: {link_to_id ??
|
||||
'-- not set --'} (files: {$lq__hosted_file_obj_li?.length ?? 'None'})"
|
||||
>
|
||||
<span class="fas fa-folder-open mx-1"></span>
|
||||
{@html $lq__hosted_file_obj_li
|
||||
? `${$lq__hosted_file_obj_li.length}×`
|
||||
: '-- none --'}
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<div class="flex flex-row flex-wrap items-center justify-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
console.log('*** Refresh button clicked ***');
|
||||
<div class="flex flex-row flex-wrap items-center justify-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
console.log('*** Refresh button clicked ***');
|
||||
|
||||
db_core.file.clear();
|
||||
db_core.file.clear();
|
||||
|
||||
// let params = {
|
||||
// qry__enabled: 'all',
|
||||
// qry__hidden: 'all',
|
||||
// }
|
||||
// let params = {
|
||||
// qry__enabled: 'all',
|
||||
// qry__hidden: 'all',
|
||||
// }
|
||||
|
||||
core_func.load_ae_obj_li__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
for_obj_type: link_to_type,
|
||||
for_obj_id: link_to_id,
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
limit: 250,
|
||||
// params: params,
|
||||
try_cache: true,
|
||||
log_lvl: 2
|
||||
});
|
||||
core_func.load_ae_obj_li__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
for_obj_type: link_to_type,
|
||||
for_obj_id: link_to_id,
|
||||
enabled: 'enabled',
|
||||
hidden: 'not_hidden',
|
||||
limit: 250,
|
||||
// params: params,
|
||||
try_cache: true,
|
||||
log_lvl: 2
|
||||
});
|
||||
|
||||
// ae_tmp.show__file_li = false;
|
||||
// console.log(`$lq__hosted_file_obj_li:`, $lq__hosted_file_obj_li);
|
||||
// $slct_trigger = 'load__hosted_file_obj_li';
|
||||
// ae_tmp.show__file_li = true;
|
||||
}}
|
||||
class="btn btn-sm p-1 m-1 preset-tonal-tertiary hover:preset-tonal-warning border border-warning-500 transition hover:transition-all *:hover:inline"
|
||||
class:hidden={!$ae_loc.edit_mode || !$ae_loc.authenticated_access}
|
||||
title="Refresh the list of files"
|
||||
>
|
||||
<span class="fas fa-sync-alt m-1"></span>
|
||||
<div class="hidden">Files</div>
|
||||
</button>
|
||||
// ae_tmp.show__file_li = false;
|
||||
// console.log(`$lq__hosted_file_obj_li:`, $lq__hosted_file_obj_li);
|
||||
// $slct_trigger = 'load__hosted_file_obj_li';
|
||||
// ae_tmp.show__file_li = true;
|
||||
}}
|
||||
class="btn btn-sm p-1 m-1 preset-tonal-tertiary hover:preset-tonal-warning border border-warning-500 transition hover:transition-all *:hover:inline"
|
||||
class:hidden={!$ae_loc.edit_mode || !$ae_loc.authenticated_access}
|
||||
title="Refresh the list of files"
|
||||
>
|
||||
<span class="fas fa-sync-alt m-1"></span>
|
||||
<div class="hidden">Files</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
console.log('*** Show Alt Download button clicked ***');
|
||||
ae_tmp.show__direct_download = !ae_tmp.show__direct_download;
|
||||
}}
|
||||
class="btn btn-sm p-1 m-1 preset-tonal-tertiary hover:preset-tonal-warning border border-warning-500 transition hover:transition-all *:hover:inline"
|
||||
class:hidden={!$ae_loc.edit_mode || !$ae_loc.trusted_access}
|
||||
title="Toggle direct download link and copy link button"
|
||||
>
|
||||
<span class="fas fa-download m-1"></span>
|
||||
<div class="hidden">
|
||||
{ae_tmp.show__direct_download ? 'Alt On' : 'Alt Download Off'}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onclick={() => {
|
||||
console.log('*** Show Alt Download button clicked ***');
|
||||
ae_tmp.show__direct_download = !ae_tmp.show__direct_download;
|
||||
}}
|
||||
class="btn btn-sm p-1 m-1 preset-tonal-tertiary hover:preset-tonal-warning border border-warning-500 transition hover:transition-all *:hover:inline"
|
||||
class:hidden={!$ae_loc.edit_mode || !$ae_loc.trusted_access}
|
||||
title="Toggle direct download link and copy link button"
|
||||
>
|
||||
<span class="fas fa-download m-1"></span>
|
||||
<div class="hidden">
|
||||
{ae_tmp.show__direct_download ? 'Alt On' : 'Alt Download Off'}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if $lq__hosted_file_obj_li && $lq__hosted_file_obj_li.length}
|
||||
<div class="overflow-auto w-full">
|
||||
<ol class="list-decimal list-inside">
|
||||
{#each [...$lq__hosted_file_obj_li].reverse().slice(0, max_file_count) as hosted_file_obj}
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.trusted_access}
|
||||
onclick={() => {
|
||||
// This (uploaded_file_kv) is referenced by other AE components. Currently it is only used for the video clipper. This should be a toggle of Add/Remove.
|
||||
if ($ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id]) {
|
||||
delete $ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id];
|
||||
$ae_loc.files.uploaded_file_kv = { ...$ae_loc.files.uploaded_file_kv };
|
||||
{#if $lq__hosted_file_obj_li && $lq__hosted_file_obj_li.length}
|
||||
<div class="overflow-auto w-full">
|
||||
<ol class="list-decimal list-inside">
|
||||
{#each [...$lq__hosted_file_obj_li]
|
||||
.reverse()
|
||||
.slice(0, max_file_count) as hosted_file_obj}
|
||||
<li>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.trusted_access}
|
||||
onclick={() => {
|
||||
// This (uploaded_file_kv) is referenced by other AE components. Currently it is only used for the video clipper. This should be a toggle of Add/Remove.
|
||||
if (
|
||||
$ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id]
|
||||
) {
|
||||
delete $ae_loc.files.uploaded_file_kv[
|
||||
hosted_file_obj.hosted_file_id
|
||||
];
|
||||
$ae_loc.files.uploaded_file_kv = {
|
||||
...$ae_loc.files.uploaded_file_kv
|
||||
};
|
||||
|
||||
delete slct_hosted_file_kv[hosted_file_obj.hosted_file_id];
|
||||
slct_hosted_file_id = null;
|
||||
slct_hosted_file_obj = null;
|
||||
} else {
|
||||
$ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id] = hosted_file_obj;
|
||||
lq__hosted_file_obj_li[hosted_file_obj.hosted_file_id] = hosted_file_obj;
|
||||
delete slct_hosted_file_kv[hosted_file_obj.hosted_file_id];
|
||||
slct_hosted_file_id = null;
|
||||
slct_hosted_file_obj = null;
|
||||
} else {
|
||||
$ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id] =
|
||||
hosted_file_obj;
|
||||
lq__hosted_file_obj_li[hosted_file_obj.hosted_file_id] =
|
||||
hosted_file_obj;
|
||||
|
||||
slct_hosted_file_kv[hosted_file_obj.hosted_file_id] = hosted_file_obj;
|
||||
slct_hosted_file_id = hosted_file_obj.hosted_file_id;
|
||||
slct_hosted_file_obj = hosted_file_obj;
|
||||
}
|
||||
log_lvl = 1;
|
||||
if (log_lvl) {
|
||||
console.log(`slct_hosted_file_kv:`, slct_hosted_file_kv);
|
||||
}
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-secondary hover:preset-filled-secondary-500"
|
||||
title="Add/Remove file to/from the locally stored uploaded file list. This is referenced by other AE components."
|
||||
>
|
||||
{#if $ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id]}
|
||||
<span class="fas fa-minus-circle m-1"></span>
|
||||
<span class="hidden">Remove</span>
|
||||
{:else}
|
||||
<span class="fas fa-plus-circle m-1"></span>
|
||||
<span class="hidden">Add</span>
|
||||
{/if}
|
||||
</button>
|
||||
slct_hosted_file_kv[hosted_file_obj.hosted_file_id] =
|
||||
hosted_file_obj;
|
||||
slct_hosted_file_id = hosted_file_obj.hosted_file_id;
|
||||
slct_hosted_file_obj = hosted_file_obj;
|
||||
}
|
||||
log_lvl = 1;
|
||||
if (log_lvl) {
|
||||
console.log(`slct_hosted_file_kv:`, slct_hosted_file_kv);
|
||||
}
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-secondary hover:preset-filled-secondary-500"
|
||||
title="Add/Remove file to/from the locally stored uploaded file list. This is referenced by other AE components."
|
||||
>
|
||||
{#if $ae_loc.files.uploaded_file_kv[hosted_file_obj.hosted_file_id]}
|
||||
<span class="fas fa-minus-circle m-1"></span>
|
||||
<span class="hidden">Remove</span>
|
||||
{:else}
|
||||
<span class="fas fa-plus-circle m-1"></span>
|
||||
<span class="hidden">Add</span>
|
||||
{/if}
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.administrator_access}
|
||||
onclick={() => {
|
||||
if (
|
||||
!confirm(
|
||||
`Are you sure you want to delete this hosted file?\n${hosted_file_obj.filename} [${hosted_file_obj.hosted_file_id_random}]`
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.administrator_access}
|
||||
onclick={() => {
|
||||
if (
|
||||
!confirm(
|
||||
`Are you sure you want to delete this hosted file?\n${hosted_file_obj.filename} [${hosted_file_obj.hosted_file_id_random}]`
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ae_promises.delete__hosted_file_obj = core_func.delete_ae_obj_id__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: hosted_file_obj.hosted_file_id_random,
|
||||
link_to_type: link_to_type,
|
||||
link_to_id: link_to_id,
|
||||
rm_orphan: true,
|
||||
fake_delete: false,
|
||||
log_lvl: 1
|
||||
});
|
||||
}}
|
||||
class:hidden={!$ae_loc.administrator_access}
|
||||
class="btn btn-sm preset-tonal-secondary hover:preset-filled-secondary-500"
|
||||
title="Delete a file from the host server."
|
||||
>
|
||||
<span class="fas fa-trash-alt m-1"></span>
|
||||
<span class="hidden">Delete</span>
|
||||
</button>
|
||||
ae_promises.delete__hosted_file_obj =
|
||||
core_func.delete_ae_obj_id__hosted_file({
|
||||
api_cfg: $ae_api,
|
||||
hosted_file_id: hosted_file_obj.hosted_file_id_random,
|
||||
link_to_type: link_to_type,
|
||||
link_to_id: link_to_id,
|
||||
rm_orphan: true,
|
||||
fake_delete: false,
|
||||
log_lvl: 1
|
||||
});
|
||||
}}
|
||||
class:hidden={!$ae_loc.administrator_access}
|
||||
class="btn btn-sm preset-tonal-secondary hover:preset-filled-secondary-500"
|
||||
title="Delete a file from the host server."
|
||||
>
|
||||
<span class="fas fa-trash-alt m-1"></span>
|
||||
<span class="hidden">Delete</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.administrator_access}
|
||||
class:hidden={!$ae_loc.administrator_access}
|
||||
onclick={() => {
|
||||
// This should show/hide the editable fields for the file. This might need to be in a little modal.
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
|
||||
title="Edit file details"
|
||||
>
|
||||
<span class="fas fa-edit m-1"></span>
|
||||
<span class="hidden">Edit</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!$ae_loc.administrator_access}
|
||||
class:hidden={!$ae_loc.administrator_access}
|
||||
onclick={() => {
|
||||
// This should show/hide the editable fields for the file. This might need to be in a little modal.
|
||||
}}
|
||||
class="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500"
|
||||
title="Edit file details"
|
||||
>
|
||||
<span class="fas fa-edit m-1"></span>
|
||||
<span class="hidden">Edit</span>
|
||||
</button>
|
||||
|
||||
<span class="text-xs text-gray-500">
|
||||
<span class="fas fa-calendar-day mx-1"></span>
|
||||
<span class="hidden">Created on:</span>
|
||||
{ae_util.iso_datetime_formatter(hosted_file_obj.created_on, 'datetime_medium_sec')}
|
||||
{#if hosted_file_obj.updated_on}
|
||||
<span class="fas fa-sync-alt mx-1"></span>
|
||||
Updated on
|
||||
{ae_util.iso_datetime_formatter(hosted_file_obj.updated_on, 'datetime_medium_sec')}
|
||||
{/if}
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
<span class="fas fa-calendar-day mx-1"></span>
|
||||
<span class="hidden">Created on:</span>
|
||||
{ae_util.iso_datetime_formatter(
|
||||
hosted_file_obj.created_on,
|
||||
'datetime_medium_sec'
|
||||
)}
|
||||
{#if hosted_file_obj.updated_on}
|
||||
<span class="fas fa-sync-alt mx-1"></span>
|
||||
Updated on
|
||||
{ae_util.iso_datetime_formatter(
|
||||
hosted_file_obj.updated_on,
|
||||
'datetime_medium_sec'
|
||||
)}
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<span class="text-sm font-semibold">
|
||||
<!-- <a href="" class="underline text-blue-500"> -->
|
||||
{hosted_file_obj.filename}
|
||||
<!-- </a> -->
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
{ae_util.format_bytes(hosted_file_obj.size)}
|
||||
</span>
|
||||
<span class="text-sm font-semibold">
|
||||
<!-- <a href="" class="underline text-blue-500"> -->
|
||||
{hosted_file_obj.filename}
|
||||
<!-- </a> -->
|
||||
</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
{ae_util.format_bytes(hosted_file_obj.size)}
|
||||
</span>
|
||||
|
||||
<span class:hidden={!$ae_loc.edit_mode} class="text-xs text-gray-500">
|
||||
{hosted_file_obj.hash_sha256?.slice(0, 5)}...
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="w-96 text-center text-gray-500" class:hidden={display_mode != 'default'}>
|
||||
No files available to display
|
||||
</p>
|
||||
{/if}
|
||||
<span class:hidden={!$ae_loc.edit_mode} class="text-xs text-gray-500">
|
||||
{hosted_file_obj.hash_sha256?.slice(0, 5)}...
|
||||
</span>
|
||||
</li>
|
||||
{/each}
|
||||
</ol>
|
||||
</div>
|
||||
{:else}
|
||||
<p class="w-96 text-center text-gray-500" class:hidden={display_mode != 'default'}>
|
||||
No files available to display
|
||||
</p>
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,120 +1,120 @@
|
||||
<script lang="ts">
|
||||
// NEW NEW NEW: 2025-01-07
|
||||
import { liveQuery } from 'dexie';
|
||||
// NEW NEW NEW: 2025-01-07
|
||||
import { liveQuery } from 'dexie';
|
||||
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import Element_manage_hosted_file_li from '$lib/elements/element_manage_hosted_file_li.svelte';
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// import { api } from '$lib/api';
|
||||
// import Element_ae_crud from '$lib/element_ae_crud.svelte';
|
||||
// import Element_data_store from '$lib/element_data_store_v2.svelte';
|
||||
import Element_manage_hosted_file_li from '$lib/elements/element_manage_hosted_file_li.svelte';
|
||||
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/stores/ae_events_stores';
|
||||
// import { core_func } from '$lib/ae_core_functions';
|
||||
// import { ae_loc, ae_sess, ae_api, ae_trig, slct, slct_trigger } from '$lib/ae_stores';
|
||||
import { db_core } from '$lib/ae_core/db_core';
|
||||
// import { events_loc, events_sess, events_slct, events_trigger } from '$lib/stores/ae_events_stores';
|
||||
|
||||
interface Props {
|
||||
// import { events_func } from '$lib/ae_events_functions';
|
||||
class_li_default?: string; // |Array<string>;
|
||||
class_li?: string; // |Array<string>;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
allow_basic?: boolean; // Not used yet
|
||||
allow_moderator?: boolean; // Not used yet
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
max_file_count?: number;
|
||||
file_type?: string; // 'image', 'video', 'audio', 'document', 'other'
|
||||
slct_hosted_file_kv?: key_val;
|
||||
slct_hosted_file_id?: any;
|
||||
slct_hosted_file_obj?: any;
|
||||
}
|
||||
interface Props {
|
||||
// import { events_func } from '$lib/ae_events_functions';
|
||||
class_li_default?: string; // |Array<string>;
|
||||
class_li?: string; // |Array<string>;
|
||||
link_to_type: string;
|
||||
link_to_id: string;
|
||||
allow_basic?: boolean; // Not used yet
|
||||
allow_moderator?: boolean; // Not used yet
|
||||
display_mode?: string; // 'default', 'compact', 'minimal', 'launcher'
|
||||
max_file_count?: number;
|
||||
file_type?: string; // 'image', 'video', 'audio', 'document', 'other'
|
||||
slct_hosted_file_kv?: key_val;
|
||||
slct_hosted_file_id?: any;
|
||||
slct_hosted_file_obj?: any;
|
||||
}
|
||||
|
||||
let {
|
||||
class_li_default,
|
||||
class_li,
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
allow_basic = false,
|
||||
allow_moderator = false,
|
||||
display_mode = 'default',
|
||||
max_file_count = 49,
|
||||
file_type = 'all',
|
||||
slct_hosted_file_kv = $bindable({}),
|
||||
slct_hosted_file_id = $bindable(null),
|
||||
slct_hosted_file_obj = $bindable(null)
|
||||
}: Props = $props();
|
||||
let {
|
||||
class_li_default,
|
||||
class_li,
|
||||
link_to_type,
|
||||
link_to_id,
|
||||
allow_basic = false,
|
||||
allow_moderator = false,
|
||||
display_mode = 'default',
|
||||
max_file_count = 49,
|
||||
file_type = 'all',
|
||||
slct_hosted_file_kv = $bindable({}),
|
||||
slct_hosted_file_id = $bindable(null),
|
||||
slct_hosted_file_obj = $bindable(null)
|
||||
}: Props = $props();
|
||||
|
||||
console.log(`HERE HERE HERE HERE: link_to_type: ${link_to_type} link_to_id: ${link_to_id}`);
|
||||
console.log(`HERE HERE HERE HERE: link_to_type: ${link_to_type} link_to_id: ${link_to_id}`);
|
||||
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
// export let show_convert_btn: null|boolean = null;
|
||||
|
||||
// let ae_placeholder_li: key_val = {};
|
||||
// let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = {};
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = false;
|
||||
// let ae_triggers: key_val = {};
|
||||
// let ae_placeholder_li: key_val = {};
|
||||
// let ae_promises: key_val = {};
|
||||
let ae_tmp: key_val = {};
|
||||
ae_tmp.show__file_li = true;
|
||||
ae_tmp.show__direct_download = false;
|
||||
// let ae_triggers: key_val = {};
|
||||
|
||||
let dq__where_val: string = `${link_to_type}_id`; // no more _random ???
|
||||
let dq__where_eq_val: string = link_to_id;
|
||||
let dq__where_val: string = `${link_to_type}_id`; // no more _random ???
|
||||
let dq__where_eq_val: string = link_to_id;
|
||||
|
||||
// This should include all files that are associated with an object (event, location, session, presenter, etc.)
|
||||
// I am not sure why, but doing reverse() and then sortBy() seems to sort in descending order.
|
||||
let lq__hosted_file_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
// console.log(`dq__where_val: ${dq__where_val}`);
|
||||
// console.log(`dq__where_eq_val: ${dq__where_eq_val}`);
|
||||
let results = null;
|
||||
if (file_type == 'all' || !file_type) {
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.sortBy('created_on');
|
||||
} else if (file_type == 'video') {
|
||||
// Handle video/mp4, video/mov, video/webm. If the content type is prefixed with "video/", then it is a video file.
|
||||
let extension = 'mp4';
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
// .and((x) => (x.extension == extension))
|
||||
// .and((x) => (x.content_type == `video/${extension}`))
|
||||
.and((x) => x.content_type.startsWith('video/'))
|
||||
// .reverse()
|
||||
.sortBy('created_on');
|
||||
// .toArray()
|
||||
} else if (file_type == 'audio') {
|
||||
// Handle audio/mp3, audio/wav, audio/ogg. If the content type is prefixed with "audio/", then it is an audio file.
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((x) => x.content_type.startsWith('audio/'))
|
||||
.sortBy('created_on');
|
||||
} else if (file_type == 'image') {
|
||||
// Handle image/jpeg, image/png, image/gif. If the content type is prefixed with "image/", then it is an image file.
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((x) => x.content_type.startsWith('image/'))
|
||||
.sortBy('created_on');
|
||||
} else if (file_type == 'document') {
|
||||
// Handle application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation. If the content type is prefixed with "application/", then it is a document file.
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((x) => x.content_type.startsWith('application/'))
|
||||
.sortBy('created_on');
|
||||
} else {
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
// .reverse()
|
||||
.sortBy('created_on');
|
||||
}
|
||||
// This should include all files that are associated with an object (event, location, session, presenter, etc.)
|
||||
// I am not sure why, but doing reverse() and then sortBy() seems to sort in descending order.
|
||||
let lq__hosted_file_obj_li = $derived(
|
||||
liveQuery(async () => {
|
||||
// console.log(`dq__where_val: ${dq__where_val}`);
|
||||
// console.log(`dq__where_eq_val: ${dq__where_eq_val}`);
|
||||
let results = null;
|
||||
if (file_type == 'all' || !file_type) {
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.sortBy('created_on');
|
||||
} else if (file_type == 'video') {
|
||||
// Handle video/mp4, video/mov, video/webm. If the content type is prefixed with "video/", then it is a video file.
|
||||
let extension = 'mp4';
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
// .and((x) => (x.extension == extension))
|
||||
// .and((x) => (x.content_type == `video/${extension}`))
|
||||
.and((x) => x.content_type.startsWith('video/'))
|
||||
// .reverse()
|
||||
.sortBy('created_on');
|
||||
// .toArray()
|
||||
} else if (file_type == 'audio') {
|
||||
// Handle audio/mp3, audio/wav, audio/ogg. If the content type is prefixed with "audio/", then it is an audio file.
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((x) => x.content_type.startsWith('audio/'))
|
||||
.sortBy('created_on');
|
||||
} else if (file_type == 'image') {
|
||||
// Handle image/jpeg, image/png, image/gif. If the content type is prefixed with "image/", then it is an image file.
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((x) => x.content_type.startsWith('image/'))
|
||||
.sortBy('created_on');
|
||||
} else if (file_type == 'document') {
|
||||
// Handle application/pdf, application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.ms-excel, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-powerpoint, application/vnd.openxmlformats-officedocument.presentationml.presentation. If the content type is prefixed with "application/", then it is a document file.
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
.and((x) => x.content_type.startsWith('application/'))
|
||||
.sortBy('created_on');
|
||||
} else {
|
||||
results = await db_core.file
|
||||
.where(dq__where_val)
|
||||
.equals(dq__where_eq_val)
|
||||
// .reverse()
|
||||
.sortBy('created_on');
|
||||
}
|
||||
|
||||
return results;
|
||||
})
|
||||
);
|
||||
return results;
|
||||
})
|
||||
);
|
||||
</script>
|
||||
|
||||
<!-- {#if lq__hosted_file_obj_li}
|
||||
@@ -133,21 +133,21 @@
|
||||
{/if} -->
|
||||
|
||||
{#if lq__hosted_file_obj_li}
|
||||
<Element_manage_hosted_file_li
|
||||
{link_to_type}
|
||||
{link_to_id}
|
||||
{lq__hosted_file_obj_li}
|
||||
{class_li_default}
|
||||
{class_li}
|
||||
{display_mode}
|
||||
bind:max_file_count
|
||||
bind:file_type
|
||||
bind:slct_hosted_file_kv
|
||||
bind:slct_hosted_file_id
|
||||
bind:slct_hosted_file_obj
|
||||
/>
|
||||
<!-- allow_basic={allow_basic} -->
|
||||
<!-- allow_moderator={allow_moderator} -->
|
||||
<Element_manage_hosted_file_li
|
||||
{link_to_type}
|
||||
{link_to_id}
|
||||
{lq__hosted_file_obj_li}
|
||||
{class_li_default}
|
||||
{class_li}
|
||||
{display_mode}
|
||||
bind:max_file_count
|
||||
bind:file_type
|
||||
bind:slct_hosted_file_kv
|
||||
bind:slct_hosted_file_id
|
||||
bind:slct_hosted_file_obj
|
||||
/>
|
||||
<!-- allow_basic={allow_basic} -->
|
||||
<!-- allow_moderator={allow_moderator} -->
|
||||
{:else}
|
||||
<p>No files found</p>
|
||||
<p>No files found</p>
|
||||
{/if}
|
||||
|
||||
@@ -1,49 +1,49 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
// This (ae) is only used for utilities
|
||||
// import { ae } from 'aether_npm_lib';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
// This (ae) is only used for utilities
|
||||
// import { ae } from 'aether_npm_lib';
|
||||
import { ae_util } from '$lib/ae_utils/ae_utils';
|
||||
|
||||
// These (slct_*) are only used internally for this component. Not needed???
|
||||
// import { slct_obj_id, slct_obj_li_type, slct_obj_type } from '../admin/stores_admin.js';
|
||||
// These (slct_*) are only used internally for this component. Not needed???
|
||||
// import { slct_obj_id, slct_obj_li_type, slct_obj_type } from '../admin/stores_admin.js';
|
||||
|
||||
// Should these slct_* be exported???
|
||||
let slct_obj_id = null;
|
||||
let slct_obj_li_type = null;
|
||||
let slct_obj_type = null;
|
||||
// Should these slct_* be exported???
|
||||
let slct_obj_id = null;
|
||||
let slct_obj_li_type = null;
|
||||
let slct_obj_type = null;
|
||||
|
||||
export let row_header: boolean = false;
|
||||
export let primary_obj_li_type: string = slct_obj_li_type; // account, person, user, event, event_session, membership_person
|
||||
export let obj = null;
|
||||
console.log(obj);
|
||||
console.log(typeof obj);
|
||||
export let row_header: boolean = false;
|
||||
export let primary_obj_li_type: string = slct_obj_li_type; // account, person, user, event, event_session, membership_person
|
||||
export let obj = null;
|
||||
console.log(obj);
|
||||
console.log(typeof obj);
|
||||
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element Object Table Row');
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element Object Table Row');
|
||||
|
||||
if (obj) {
|
||||
console.log('Table Row Object:', obj);
|
||||
// console.log(typeof obj);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (obj) {
|
||||
console.log('Table Row Object:', obj);
|
||||
// console.log(typeof obj);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
/* BEGIN: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
|
||||
/* END: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
|
||||
/* BEGIN: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
|
||||
/* END: Handle requests (archive, create, hide, remove, select, update, POST, PATCH, GET, DELETE) */
|
||||
|
||||
/* BEGIN: Handle other local actions (show/hide form, process data) */
|
||||
/* END: Handle other local actions (show/hide form, process data) */
|
||||
/* BEGIN: Handle other local actions (show/hide form, process data) */
|
||||
/* END: Handle other local actions (show/hide form, process data) */
|
||||
|
||||
/* BEGIN: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
|
||||
/* END: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
|
||||
/* BEGIN: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
|
||||
/* END: Handle children events (archived, canceled, closed, created, deleted, hidden, updated) */
|
||||
</script>
|
||||
|
||||
<tr>
|
||||
{#if obj != null && typeof obj == 'object'}
|
||||
{#each Object.entries(obj) as [obj_prop_name, obj_prop_value]}
|
||||
<!-- NEED TO ADD A CHECK IF:
|
||||
{#if obj != null && typeof obj == 'object'}
|
||||
{#each Object.entries(obj) as [obj_prop_name, obj_prop_value]}
|
||||
<!-- NEED TO ADD A CHECK IF:
|
||||
NOTE:
|
||||
NOTE:
|
||||
|
||||
@@ -55,104 +55,106 @@
|
||||
NOTE:
|
||||
-->
|
||||
|
||||
{#if obj_prop_name.endsWith('_id_random') || obj_prop_name == 'for_type' || obj_prop_name == 'for_id'}
|
||||
{#if row_header}
|
||||
<th
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() => (primary_obj_li_type = obj_prop_name.replace('_id_random', ''))}
|
||||
>
|
||||
{ae_util.set_obj_prop_display_name({
|
||||
prop_name: obj_prop_name,
|
||||
obj_type: primary_obj_li_type
|
||||
})}
|
||||
</th>
|
||||
{:else}
|
||||
<td
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() => {
|
||||
slct_obj_type = obj_prop_name.replace('_id_random', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
on:keypress={() => {
|
||||
slct_obj_type = obj_prop_name.replace('_id_random', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
>
|
||||
<!-- {obj_prop_value} -->
|
||||
{#if obj_prop_name.endsWith('_id_random') || obj_prop_name == 'for_type' || obj_prop_name == 'for_id'}
|
||||
{#if row_header}
|
||||
<th
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() =>
|
||||
(primary_obj_li_type = obj_prop_name.replace('_id_random', ''))}
|
||||
>
|
||||
{ae_util.set_obj_prop_display_name({
|
||||
prop_name: obj_prop_name,
|
||||
obj_type: primary_obj_li_type
|
||||
})}
|
||||
</th>
|
||||
{:else}
|
||||
<td
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() => {
|
||||
slct_obj_type = obj_prop_name.replace('_id_random', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
on:keypress={() => {
|
||||
slct_obj_type = obj_prop_name.replace('_id_random', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
>
|
||||
<!-- {obj_prop_value} -->
|
||||
|
||||
<!-- {#if (obj_prop_value && obj_prop_value.length > 25)}
|
||||
<!-- {#if (obj_prop_value && obj_prop_value.length > 25)}
|
||||
{obj_prop_value.substring(0,25)}
|
||||
{:else} -->
|
||||
{#if obj_prop_value}
|
||||
<a
|
||||
href="/{ae_util.return_obj_type_path({
|
||||
obj_type_prop_name: obj_prop_name
|
||||
})}/{obj_prop_value}"
|
||||
>
|
||||
{obj_prop_value.substring(0, 25)}
|
||||
</a>
|
||||
{:else}
|
||||
<!-- {obj_prop_value} -->
|
||||
<span class="fs_smaller">-- None --</span>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
{:else if obj_prop_name.endsWith('[URL]')}
|
||||
{#if row_header}
|
||||
<th
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() => (primary_obj_li_type = obj_prop_name.replaceAll('[URL]', ''))}
|
||||
>
|
||||
{ae_util.set_obj_prop_display_name({
|
||||
prop_name: obj_prop_name.replaceAll('[URL]', ''),
|
||||
obj_type: primary_obj_li_type
|
||||
})}
|
||||
</th>
|
||||
{:else}
|
||||
<td
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() => {
|
||||
slct_obj_type = obj_prop_name.replaceAll('[URL]', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
on:keypress={() => {
|
||||
slct_obj_type = obj_prop_name.replaceAll('[URL]', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
>
|
||||
<a href={obj_prop_value}>{obj_prop_value}</a>
|
||||
</td>
|
||||
{/if}
|
||||
{:else if row_header}
|
||||
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
|
||||
{ae_util.set_obj_prop_display_name({
|
||||
prop_name: obj_prop_name,
|
||||
obj_type: primary_obj_li_type
|
||||
})}
|
||||
</th>
|
||||
{:else}
|
||||
<td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
|
||||
{#if obj_prop_value}
|
||||
{#if obj_prop_value && obj_prop_value.length > 25}
|
||||
{obj_prop_value.substring(0, 25)} ...
|
||||
{:else}
|
||||
{obj_prop_value}
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="fs_smaller">-- None --</span>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
<!-- <td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>{obj_prop_value}</td> -->
|
||||
{/each}
|
||||
{:else}
|
||||
<!-- This should never happen -->
|
||||
<td class="fs_smaller" colspan="100"> -- Not Set -- </td>
|
||||
{/if}
|
||||
{#if obj_prop_value}
|
||||
<a
|
||||
href="/{ae_util.return_obj_type_path({
|
||||
obj_type_prop_name: obj_prop_name
|
||||
})}/{obj_prop_value}"
|
||||
>
|
||||
{obj_prop_value.substring(0, 25)}
|
||||
</a>
|
||||
{:else}
|
||||
<!-- {obj_prop_value} -->
|
||||
<span class="fs_smaller">-- None --</span>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
{:else if obj_prop_name.endsWith('[URL]')}
|
||||
{#if row_header}
|
||||
<th
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() =>
|
||||
(primary_obj_li_type = obj_prop_name.replaceAll('[URL]', ''))}
|
||||
>
|
||||
{ae_util.set_obj_prop_display_name({
|
||||
prop_name: obj_prop_name.replaceAll('[URL]', ''),
|
||||
obj_type: primary_obj_li_type
|
||||
})}
|
||||
</th>
|
||||
{:else}
|
||||
<td
|
||||
data-obj_type={primary_obj_li_type}
|
||||
data-obj_prop_name={obj_prop_name}
|
||||
on:click={() => {
|
||||
slct_obj_type = obj_prop_name.replaceAll('[URL]', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
on:keypress={() => {
|
||||
slct_obj_type = obj_prop_name.replaceAll('[URL]', '');
|
||||
slct_obj_id = obj_prop_value;
|
||||
}}
|
||||
>
|
||||
<a href={obj_prop_value}>{obj_prop_value}</a>
|
||||
</td>
|
||||
{/if}
|
||||
{:else if row_header}
|
||||
<th data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
|
||||
{ae_util.set_obj_prop_display_name({
|
||||
prop_name: obj_prop_name,
|
||||
obj_type: primary_obj_li_type
|
||||
})}
|
||||
</th>
|
||||
{:else}
|
||||
<td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>
|
||||
{#if obj_prop_value}
|
||||
{#if obj_prop_value && obj_prop_value.length > 25}
|
||||
{obj_prop_value.substring(0, 25)} ...
|
||||
{:else}
|
||||
{obj_prop_value}
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="fs_smaller">-- None --</span>
|
||||
{/if}
|
||||
</td>
|
||||
{/if}
|
||||
<!-- <td data-obj_type={primary_obj_li_type} data-obj_prop_name={obj_prop_name}>{obj_prop_value}</td> -->
|
||||
{/each}
|
||||
{:else}
|
||||
<!-- This should never happen -->
|
||||
<td class="fs_smaller" colspan="100"> -- Not Set -- </td>
|
||||
{/if}
|
||||
</tr>
|
||||
|
||||
<style lang="postcss">
|
||||
|
||||
@@ -1,146 +1,152 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
// *** Import Aether core variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { api, Element_obj_tbl_row } from 'aether_npm_lib';
|
||||
import Element_obj_tbl_row from '$lib/elements/element_obj_tbl_row.svelte';
|
||||
import { post_object } from '$lib/ae_api/api_post_object';
|
||||
// *** Import Aether core variables and functions
|
||||
import type { key_val } from '$lib/stores/ae_stores';
|
||||
// import { api, Element_obj_tbl_row } from 'aether_npm_lib';
|
||||
import Element_obj_tbl_row from '$lib/elements/element_obj_tbl_row.svelte';
|
||||
import { post_object } from '$lib/ae_api/api_post_object';
|
||||
|
||||
// *** Import Aether core components
|
||||
// import Element_obj_tbl_row from './element_obj_tbl_row.svelte';
|
||||
// *** Import Aether core components
|
||||
// import Element_obj_tbl_row from './element_obj_tbl_row.svelte';
|
||||
|
||||
// *** Import Aether module variables and functions
|
||||
// *** Import Aether module variables and functions
|
||||
|
||||
// *** Import Aether module components
|
||||
// *** Import Aether module components
|
||||
|
||||
// *** Export/Exposed variables and functions for component
|
||||
export let api_cfg: any;
|
||||
export let show_textarea = true;
|
||||
export let button_label = 'Run SQL!';
|
||||
export let show_record_count = true;
|
||||
export let remove_breaks = false;
|
||||
export let run_on_load = false;
|
||||
// *** Export/Exposed variables and functions for component
|
||||
export let api_cfg: any;
|
||||
export let show_textarea = true;
|
||||
export let button_label = 'Run SQL!';
|
||||
export let show_record_count = true;
|
||||
export let remove_breaks = false;
|
||||
export let run_on_load = false;
|
||||
|
||||
export let sql_statement: string;
|
||||
export let sql_data = null;
|
||||
export let as_list = false;
|
||||
export let log_lvl: number = 0;
|
||||
export let sql_statement: string;
|
||||
export let sql_data = null;
|
||||
export let as_list = false;
|
||||
export let log_lvl: number = 0;
|
||||
|
||||
// *** Set initial variables
|
||||
let ae_promises: key_val = {};
|
||||
let sql_qry_result: any = null;
|
||||
// *** Set initial variables
|
||||
let ae_promises: key_val = {};
|
||||
let sql_qry_result: any = null;
|
||||
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element SQL Query');
|
||||
onMount(() => {
|
||||
console.log('** Element Mounted: ** Element SQL Query');
|
||||
|
||||
if (run_on_load) {
|
||||
console.log('Run On Load');
|
||||
let result = handle_run_sql(sql_statement, sql_data, as_list, log_lvl).then((qry_result) => {
|
||||
console.log('SQL Query Result:', qry_result);
|
||||
sql_qry_result = qry_result;
|
||||
return qry_result;
|
||||
});
|
||||
}
|
||||
});
|
||||
if (run_on_load) {
|
||||
console.log('Run On Load');
|
||||
let result = handle_run_sql(sql_statement, sql_data, as_list, log_lvl).then(
|
||||
(qry_result) => {
|
||||
console.log('SQL Query Result:', qry_result);
|
||||
sql_qry_result = qry_result;
|
||||
return qry_result;
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// const dispatch = createEventDispatcher();
|
||||
// const dispatch = createEventDispatcher();
|
||||
|
||||
async function handle_run_sql(qry, data, as_list = false, log_lvl = 0) {
|
||||
console.log('*** handle_run_sql() ***');
|
||||
async function handle_run_sql(qry, data, as_list = false, log_lvl = 0) {
|
||||
console.log('*** handle_run_sql() ***');
|
||||
|
||||
let sql_qry_data: key_val = {};
|
||||
let sql_qry_data: key_val = {};
|
||||
|
||||
let endpoint = '/sql/select';
|
||||
let params: key_val = {};
|
||||
if (as_list) {
|
||||
params['as_list'] = true;
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log('Params:', params);
|
||||
}
|
||||
let endpoint = '/sql/select';
|
||||
let params: key_val = {};
|
||||
if (as_list) {
|
||||
params['as_list'] = true;
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log('Params:', params);
|
||||
}
|
||||
|
||||
if (qry) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (log_lvl > 1) {
|
||||
console.log('Qry:', qry);
|
||||
}
|
||||
if (qry) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (log_lvl > 1) {
|
||||
console.log('Qry:', qry);
|
||||
}
|
||||
|
||||
if (remove_breaks) {
|
||||
sql_qry_data['sql_qry'] = qry.replace(/(\r\n|\n|\r)/gm, '');
|
||||
} else {
|
||||
sql_qry_data['sql_qry'] = qry;
|
||||
}
|
||||
if (remove_breaks) {
|
||||
sql_qry_data['sql_qry'] = qry.replace(/(\r\n|\n|\r)/gm, '');
|
||||
} else {
|
||||
sql_qry_data['sql_qry'] = qry;
|
||||
}
|
||||
|
||||
sql_qry_data['sql_data'] = data;
|
||||
sql_qry_data['sql_data'] = data;
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('SQL Qry Data:', sql_qry_data);
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log('SQL Qry Data:', sql_qry_data);
|
||||
}
|
||||
|
||||
ae_promises.sql_qry_promise = await post_object({
|
||||
api_cfg: api_cfg,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
data: sql_qry_data,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
ae_promises.sql_qry_promise = await post_object({
|
||||
api_cfg: api_cfg,
|
||||
endpoint: endpoint,
|
||||
params: params,
|
||||
data: sql_qry_data,
|
||||
log_lvl: log_lvl
|
||||
});
|
||||
|
||||
if (log_lvl) {
|
||||
console.log('SQL Query Results', ae_promises.sql_qry_promise);
|
||||
}
|
||||
if (log_lvl) {
|
||||
console.log('SQL Query Results', ae_promises.sql_qry_promise);
|
||||
}
|
||||
|
||||
return ae_promises.sql_qry_promise;
|
||||
}
|
||||
return ae_promises.sql_qry_promise;
|
||||
}
|
||||
</script>
|
||||
|
||||
<section id="sql_qry" class="sql_qry">
|
||||
{#if show_textarea}
|
||||
<textarea class="textarea" bind:value={sql_statement}></textarea>
|
||||
{/if}
|
||||
{#if show_textarea}
|
||||
<textarea class="textarea" bind:value={sql_statement}></textarea>
|
||||
{/if}
|
||||
|
||||
<div class="text-center">
|
||||
<button
|
||||
type="button"
|
||||
on:click={async () => {
|
||||
sql_qry_result = await handle_run_sql(sql_statement, sql_data, as_list, log_lvl);
|
||||
}}
|
||||
class="btn btn-md preset-tonal-primary hover:preset-tonal-primary border border-primary-500"
|
||||
>
|
||||
{button_label}
|
||||
</button>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button
|
||||
type="button"
|
||||
on:click={async () => {
|
||||
sql_qry_result = await handle_run_sql(sql_statement, sql_data, as_list, log_lvl);
|
||||
}}
|
||||
class="btn btn-md preset-tonal-primary hover:preset-tonal-primary border border-primary-500"
|
||||
>
|
||||
{button_label}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if show_record_count && sql_qry_result && sql_qry_result.length}
|
||||
<div>
|
||||
Record count: <strong>{sql_qry_result.length}</strong>
|
||||
</div>
|
||||
{/if}
|
||||
{#if show_record_count && sql_qry_result && sql_qry_result.length}
|
||||
<div>
|
||||
Record count: <strong>{sql_qry_result.length}</strong>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="sql_statement_result">
|
||||
{#await ae_promises.sql_qry_promise}
|
||||
Getting results...
|
||||
{:then}
|
||||
{#if sql_qry_result && sql_qry_result.length}
|
||||
<table
|
||||
class="table table-compact table-bordered table-striped min-w-min sql_qry_result text-xs"
|
||||
>
|
||||
<Element_obj_tbl_row row_header={true} obj={sql_qry_result[0]} primary_obj_li_type="" />
|
||||
{#each sql_qry_result as record}
|
||||
<Element_obj_tbl_row obj={record} primary_obj_li_type="" />
|
||||
{/each}
|
||||
</table>
|
||||
{:else}
|
||||
<div>Nothing to show yet...</div>
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
<div class="sql_statement_result">
|
||||
{#await ae_promises.sql_qry_promise}
|
||||
Getting results...
|
||||
{:then}
|
||||
{#if sql_qry_result && sql_qry_result.length}
|
||||
<table
|
||||
class="table table-compact table-bordered table-striped min-w-min sql_qry_result text-xs"
|
||||
>
|
||||
<Element_obj_tbl_row
|
||||
row_header={true}
|
||||
obj={sql_qry_result[0]}
|
||||
primary_obj_li_type=""
|
||||
/>
|
||||
{#each sql_qry_result as record}
|
||||
<Element_obj_tbl_row obj={record} primary_obj_li_type="" />
|
||||
{/each}
|
||||
</table>
|
||||
{:else}
|
||||
<div>Nothing to show yet...</div>
|
||||
{/if}
|
||||
{/await}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style lang="postcss">
|
||||
/* .sql_qry textarea {
|
||||
/* .sql_qry textarea {
|
||||
width: 100%;
|
||||
height: 8em;
|
||||
} */
|
||||
|
||||
@@ -1,113 +1,113 @@
|
||||
/* Basic editor styles */
|
||||
.tiptap {
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Link styles */
|
||||
a {
|
||||
color: var(--purple);
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
/* Link styles */
|
||||
a {
|
||||
color: var(--purple);
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
color: var(--purple-contrast);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
color: var(--purple-contrast);
|
||||
}
|
||||
}
|
||||
|
||||
/* List styles */
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 1.5rem;
|
||||
// border: solid thin red;
|
||||
}
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
margin-left: 1.5rem;
|
||||
// border: solid thin red;
|
||||
}
|
||||
/* List styles */
|
||||
ul {
|
||||
list-style-type: disc;
|
||||
margin-left: 1.5rem;
|
||||
// border: solid thin red;
|
||||
}
|
||||
ol {
|
||||
list-style-type: decimal;
|
||||
margin-left: 1.5rem;
|
||||
// border: solid thin red;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
ul,
|
||||
ol {
|
||||
padding: 0 1rem;
|
||||
margin: 1.25rem 1rem 1.25rem 0.4rem;
|
||||
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
li p {
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
}
|
||||
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
/* Heading styles */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: 1.1;
|
||||
margin-top: 2.5rem;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: 3.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
/* Code and preformatted text styles */
|
||||
code {
|
||||
background-color: var(--purple-light);
|
||||
border-radius: 0.4rem;
|
||||
color: var(--black);
|
||||
font-size: 0.85rem;
|
||||
padding: 0.25em 0.3em;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
pre {
|
||||
background: var(--black);
|
||||
border-radius: 0.5rem;
|
||||
color: var(--white);
|
||||
font-family: 'JetBrainsMono', monospace;
|
||||
margin: 1.5rem 0;
|
||||
padding: 0.75rem 1rem;
|
||||
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
code {
|
||||
background: none;
|
||||
color: inherit;
|
||||
font-size: 0.8rem;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
blockquote {
|
||||
border-left: 3px solid var(--gray-3);
|
||||
margin: 1.5rem 0;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--gray-2);
|
||||
margin: 2rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user