- Replace old implementation of PROCESSOR_TYPES and CATALOG_TYPES with the new cached approach
- Add an ordered_list dynamic field type (to be refined) - Add tabulator javascript library to project
This commit is contained in:
@@ -54,6 +54,7 @@
|
||||
<hr>
|
||||
{% include 'footer.html' %}
|
||||
{% include 'scripts.html' %}
|
||||
{% include 'ordered_list_configs.html' %}
|
||||
{% block scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
231
eveai_app/templates/eveai_ordered_list_editor.html
Normal file
231
eveai_app/templates/eveai_ordered_list_editor.html
Normal file
@@ -0,0 +1,231 @@
|
||||
<script type="module">
|
||||
window.EveAI = window.EveAI || {};
|
||||
window.EveAI.OrderedListEditors = {
|
||||
instances: {},
|
||||
initialize: function(containerId, data, listType, options = {}) {
|
||||
console.log('Initializing OrderedListEditor for', containerId, 'with data', data, 'and listType', listType);
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container || typeof container !== 'object' || !('classList' in container)) {
|
||||
console.error(`Container with ID ${containerId} not found or not a valid element:`, container);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.instances[containerId]) return this.instances[containerId];
|
||||
|
||||
if (typeof window.Tabulator !== 'function') {
|
||||
console.error('Tabulator not loaded (window.Tabulator missing).');
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error:</strong> Tabulator not loaded
|
||||
</div>`;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the list type configuration
|
||||
const listTypeConfig = this._getListTypeConfig(listType);
|
||||
if (!listTypeConfig) {
|
||||
console.error(`List type configuration for ${listType} not found.`);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error:</strong> List type configuration for ${listType} not found
|
||||
</div>`;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create column definitions from list type
|
||||
const columns = this._createColumnsFromListType(listTypeConfig);
|
||||
|
||||
// Initialize Tabulator
|
||||
try {
|
||||
console.log('Creating Tabulator for', containerId);
|
||||
const table = new Tabulator(container, {
|
||||
data: data || [],
|
||||
columns: columns,
|
||||
layout: "fitColumns",
|
||||
movableRows: true,
|
||||
height: "400px",
|
||||
...options
|
||||
});
|
||||
|
||||
console.log('Tabulator created for', containerId);
|
||||
container.classList.add('tabulator-initialized');
|
||||
|
||||
// Add row button
|
||||
const addRowBtn = document.createElement('button');
|
||||
addRowBtn.className = 'btn btn-sm btn-primary mt-2';
|
||||
addRowBtn.innerHTML = 'Add Row';
|
||||
addRowBtn.addEventListener('click', () => {
|
||||
const newRow = {};
|
||||
// Create empty row with default values
|
||||
Object.entries(listTypeConfig).forEach(([key, field]) => {
|
||||
newRow[key] = field.default || '';
|
||||
});
|
||||
table.addRow(newRow);
|
||||
this._updateTextarea(containerId, table);
|
||||
});
|
||||
container.parentNode.insertBefore(addRowBtn, container.nextSibling);
|
||||
|
||||
// Store instance
|
||||
this.instances[containerId] = {
|
||||
table: table,
|
||||
textarea: document.getElementById(containerId.replace('-editor', ''))
|
||||
};
|
||||
|
||||
// Update textarea on data change
|
||||
table.on("dataChanged", () => {
|
||||
this._updateTextarea(containerId, table);
|
||||
});
|
||||
|
||||
return table;
|
||||
} catch (e) {
|
||||
console.error(`Error initializing Tabulator for ${containerId}:`, e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error initializing Tabulator:</strong><br>${e.message}
|
||||
</div>`;
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
_updateTextarea: function(containerId, table) {
|
||||
const instance = this.instances[containerId];
|
||||
if (instance && instance.textarea) {
|
||||
instance.textarea.value = JSON.stringify(table.getData());
|
||||
}
|
||||
},
|
||||
|
||||
_getListTypeConfig: function(listType) {
|
||||
// This would need to be implemented to fetch the list type configuration
|
||||
// Could be from a global variable set in the template or via an API call
|
||||
return window.listTypeConfigs && window.listTypeConfigs[listType];
|
||||
},
|
||||
|
||||
_createColumnsFromListType: function(listTypeConfig) {
|
||||
const columns = [];
|
||||
|
||||
// Add drag handle column for row reordering
|
||||
columns.push({
|
||||
formatter: "handle",
|
||||
headerSort: false,
|
||||
frozen: true,
|
||||
width: 30,
|
||||
minWidth: 30
|
||||
});
|
||||
|
||||
// Add columns for each field in the list type
|
||||
Object.entries(listTypeConfig).forEach(([key, field]) => {
|
||||
const column = {
|
||||
title: field.name || key,
|
||||
field: key,
|
||||
tooltip: field.description
|
||||
};
|
||||
|
||||
// Set editor based on field type
|
||||
if (field.type === 'boolean') {
|
||||
column.formatter = 'tickCross';
|
||||
column.editor = 'tickCross';
|
||||
column.hozAlign = 'center';
|
||||
} else if (field.type === 'enum' && field.allowed_values) {
|
||||
column.editor = 'select';
|
||||
column.editorParams = {
|
||||
values: field.allowed_values
|
||||
};
|
||||
} else {
|
||||
column.editor = 'input';
|
||||
}
|
||||
|
||||
columns.push(column);
|
||||
});
|
||||
|
||||
// Add delete button column
|
||||
columns.push({
|
||||
formatter: function(cell, formatterParams, onRendered) {
|
||||
return "<button class='btn btn-sm btn-danger'><i class='material-icons'>delete</i></button>";
|
||||
},
|
||||
width: 40,
|
||||
hozAlign: "center",
|
||||
headerSort: false,
|
||||
cellClick: function(e, cell) {
|
||||
cell.getRow().delete();
|
||||
}
|
||||
});
|
||||
|
||||
return columns;
|
||||
},
|
||||
|
||||
get: function(containerId) {
|
||||
return this.instances[containerId] || null;
|
||||
},
|
||||
|
||||
destroy: function(containerId) {
|
||||
if (this.instances[containerId]) {
|
||||
if (this.instances[containerId].table && typeof this.instances[containerId].table.destroy === 'function') {
|
||||
this.instances[containerId].table.destroy();
|
||||
}
|
||||
delete this.instances[containerId];
|
||||
}
|
||||
const container = document.getElementById(containerId);
|
||||
if (container) {
|
||||
container.classList.remove('tabulator-initialized');
|
||||
container.innerHTML = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize list type configurations
|
||||
window.listTypeConfigs = window.listTypeConfigs || {};
|
||||
|
||||
// Initialize ordered list editors
|
||||
document.querySelectorAll('.ordered-list-field').forEach(function(textarea) {
|
||||
const containerId = textarea.id + '-editor';
|
||||
const container = document.getElementById(containerId);
|
||||
if (!container) return;
|
||||
|
||||
try {
|
||||
const data = textarea.value ? JSON.parse(textarea.value) : [];
|
||||
const listType = textarea.getAttribute('data-list-type');
|
||||
|
||||
// Check if we have the list type configuration
|
||||
if (listType && !window.listTypeConfigs[listType]) {
|
||||
console.warn(`List type configuration for ${listType} not found. The editor may not work correctly.`);
|
||||
}
|
||||
|
||||
window.EveAI.OrderedListEditors.initialize(containerId, data, listType);
|
||||
} catch (e) {
|
||||
console.error('Error initializing ordered list editor:', e);
|
||||
container.innerHTML = `<div class="alert alert-danger p-3">
|
||||
<strong>Error initializing ordered list editor:</strong><br>${e.message}
|
||||
</div>`;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Tabulator styling */
|
||||
.ordered-list-editor {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
/* Make sure the Tabulator container has a proper height */
|
||||
.ordered-list-editor .tabulator {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
/* Style for the handle column */
|
||||
.ordered-list-editor .tabulator-row-handle {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
/* Style for the delete button */
|
||||
.ordered-list-editor .tabulator-cell button.btn-danger {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* Style for boolean columns */
|
||||
.ordered-list-editor .tabulator-cell[data-type="boolean"] {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,3 +1,12 @@
|
||||
{# Helper functie om veilig de class van een veld te krijgen #}
|
||||
{% macro get_field_class(field, default='') %}
|
||||
{% if field.render_kw is not none and field.render_kw.get('class') is not none %}
|
||||
{{ field.render_kw.get('class') }}
|
||||
{% else %}
|
||||
{{ default }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro render_field_content(field, disabled=False, readonly=False, class='') %}
|
||||
{% if field.type == 'BooleanField' %}
|
||||
<div class="form-group">
|
||||
@@ -55,9 +64,13 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% set field_class = get_field_class(field) %}
|
||||
{% if field.type == 'TextAreaField' and 'json-editor' in class %}
|
||||
<div id="{{ field.id }}-editor" class="json-editor-container"></div>
|
||||
{{ field(class="form-control d-none " + class, disabled=disabled, readonly=readonly) }}
|
||||
{% elif field.type == 'OrderedListField' or 'ordered-list-field' in field_class %}
|
||||
{# Behoud ordered-list-field class en voeg form-control toe #}
|
||||
{{ field(class="form-control " + field_class|trim, disabled=disabled, readonly=readonly) }}
|
||||
{% elif field.type == 'SelectField' %}
|
||||
{{ field(class="form-control form-select " + class, disabled=disabled, readonly=readonly) }}
|
||||
{% else %}
|
||||
@@ -76,6 +89,7 @@
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
|
||||
{% macro render_field(field, disabled_fields=[], readonly_fields=[], exclude_fields=[], class='') %}
|
||||
<!-- Debug info -->
|
||||
<!-- Field name: {{ field.name }}, Field type: {{ field.__class__.__name__ }} -->
|
||||
|
||||
7
eveai_app/templates/ordered_list_configs.html
Normal file
7
eveai_app/templates/ordered_list_configs.html
Normal file
@@ -0,0 +1,7 @@
|
||||
{# Include this template in any page that uses ordered_list fields #}
|
||||
{# Usage: {% include 'ordered_list_configs.html' %} #}
|
||||
{# The form must be available in the template context as 'form' #}
|
||||
|
||||
{% if form and form.get_list_type_configs_js %}
|
||||
{{ form.get_list_type_configs_js()|safe }}
|
||||
{% endif %}
|
||||
@@ -9,6 +9,7 @@
|
||||
<script src="{{url_for('static', filename='assets/js/material-kit-pro.min.js')}}"></script>
|
||||
|
||||
{% include 'eveai_json_editor.html' %}
|
||||
{% include 'eveai_ordered_list_editor.html' %}
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
Reference in New Issue
Block a user