1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Removed myproject/ from tracking

This commit is contained in:
Alanna Cao 2024-12-08 19:22:06 -05:00
commit 502084394c
10 changed files with 234 additions and 92 deletions

6
.gitignore vendored
View File

@ -17,3 +17,9 @@ tests/.coverage*
build/
tests/report/
tests/screenshots/
venv/
.venv/
env/
.env/
myproject/staticfiles
myproject/

View File

@ -299,7 +299,7 @@ input[type="submit"], button {
background-position: 0 -80px;
}
a.selector-chooseall, a.selector-clearall {
.selector-chooseall, .selector-clearall {
align-self: center;
}
@ -649,6 +649,7 @@ input[type="submit"], button {
.related-widget-wrapper .selector {
order: 1;
flex: 1 0 auto;
}
.related-widget-wrapper > a {

View File

@ -235,19 +235,19 @@ fieldset .fieldBox {
background-position: 0 -112px;
}
a.selector-chooseall {
.selector-chooseall {
background: url(../img/selector-icons.svg) right -128px no-repeat;
}
a.active.selector-chooseall:focus, a.active.selector-chooseall:hover {
.active.selector-chooseall:focus, .active.selector-chooseall:hover {
background-position: 100% -144px;
}
a.selector-clearall {
.selector-clearall {
background: url(../img/selector-icons.svg) 0 -160px no-repeat;
}
a.active.selector-clearall:focus, a.active.selector-clearall:hover {
.active.selector-clearall:focus, .active.selector-clearall:hover {
background-position: 0 -176px;
}

View File

@ -2,7 +2,7 @@
.selector {
display: flex;
flex-grow: 1;
flex: 1;
gap: 0 10px;
}
@ -14,17 +14,20 @@
}
.selector-available, .selector-chosen {
text-align: center;
display: flex;
flex-direction: column;
flex: 1 1;
}
.selector-available h2, .selector-chosen h2 {
.selector-available-title, .selector-chosen-title {
border: 1px solid var(--border-color);
border-radius: 4px 4px 0 0;
}
.selector .helptext {
font-size: 0.6875rem;
}
.selector-chosen .list-footer-display {
border: 1px solid var(--border-color);
border-top: none;
@ -40,14 +43,20 @@
color: var(--breadcrumbs-fg);
}
.selector-chosen h2 {
.selector-chosen-title {
background: var(--secondary);
color: var(--header-link-color);
padding: 8px;
}
.selector-chosen-title label {
color: var(--header-link-color);
}
.selector .selector-available h2 {
.selector-available-title {
background: var(--darkened-bg);
color: var(--body-quiet-color);
padding: 8px;
}
.selector .selector-filter {
@ -121,6 +130,7 @@
overflow: hidden;
cursor: default;
opacity: 0.55;
border: none;
}
.active.selector-add, .active.selector-remove {
@ -147,7 +157,7 @@
background-position: 0 -80px;
}
a.selector-chooseall, a.selector-clearall {
.selector-chooseall, .selector-clearall {
display: inline-block;
height: 16px;
text-align: left;
@ -158,38 +168,39 @@ a.selector-chooseall, a.selector-clearall {
color: var(--body-quiet-color);
text-decoration: none;
opacity: 0.55;
border: none;
}
a.active.selector-chooseall:focus, a.active.selector-clearall:focus,
a.active.selector-chooseall:hover, a.active.selector-clearall:hover {
.active.selector-chooseall:focus, .active.selector-clearall:focus,
.active.selector-chooseall:hover, .active.selector-clearall:hover {
color: var(--link-fg);
}
a.active.selector-chooseall, a.active.selector-clearall {
.active.selector-chooseall, .active.selector-clearall {
opacity: 1;
}
a.active.selector-chooseall:hover, a.active.selector-clearall:hover {
.active.selector-chooseall:hover, .active.selector-clearall:hover {
cursor: pointer;
}
a.selector-chooseall {
.selector-chooseall {
padding: 0 18px 0 0;
background: url(../img/selector-icons.svg) right -160px no-repeat;
cursor: default;
}
a.active.selector-chooseall:focus, a.active.selector-chooseall:hover {
.active.selector-chooseall:focus, .active.selector-chooseall:hover {
background-position: 100% -176px;
}
a.selector-clearall {
.selector-clearall {
padding: 0 0 0 18px;
background: url(../img/selector-icons.svg) 0 -128px no-repeat;
cursor: default;
}
a.active.selector-clearall:focus, a.active.selector-clearall:hover {
.active.selector-clearall:focus, .active.selector-clearall:hover {
background-position: 0 -144px;
}

View File

@ -16,6 +16,7 @@ Requires core.js and SelectBox.js.
from_box.id += '_from'; // change its ID
from_box.className = 'filtered';
from_box.setAttribute('aria-labelledby', field_id + '_from_title');
from_box.setAttribute('aria-labelledby', field_id + '_from_title');
for (const p of from_box.parentNode.getElementsByTagName('p')) {
if (p.classList.contains("info")) {
@ -43,11 +44,19 @@ Requires core.js and SelectBox.js.
selector_available_title.id = field_id + '_from_title';
selector_available_title.className = 'selector-available-title';
quickElement('label', selector_available_title, interpolate(gettext('Available %s') + ' ', [field_name]), 'for', field_id + '_from');
const selector_available_title = quickElement('div', selector_available);
selector_available_title.id = field_id + '_from_title';
selector_available_title.className = 'selector-available-title';
quickElement('label', selector_available_title, interpolate(gettext('Available %s') + ' ', [field_name]), 'for', field_id + '_from');
quickElement(
'p',
selector_available_title,
interpolate(gettext('Choose %s by selecting them and then select the "Choose" arrow button.'), [field_name]),
'class', 'helptext'
'p',
selector_available_title,
interpolate(gettext('Choose %s by selecting them and then select the "Choose" arrow button.'), [field_name]),
'class', 'helptext'
);
const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');
@ -59,6 +68,7 @@ Requires core.js and SelectBox.js.
'span', search_filter_label, '',
'class', 'help-tooltip search-label-icon',
'aria-label', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])
'aria-label', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])
);
filter_p.appendChild(document.createTextNode(' '));
@ -74,6 +84,13 @@ Requires core.js and SelectBox.js.
'id', field_id + '_add_all',
'class', 'selector-chooseall'
);
const choose_all = quickElement(
'button',
selector_available,
interpolate(gettext('Choose all %s'), [field_name]),
'id', field_id + '_add_all',
'class', 'selector-chooseall'
);
// <ul class="selector-chooser">
const selector_chooser = quickElement('ul', selector_div);
@ -92,6 +109,20 @@ Requires core.js and SelectBox.js.
'id', field_id + '_remove',
'class', 'selector-remove'
);
const add_button = quickElement(
'button',
quickElement('li', selector_chooser),
interpolate(gettext('Choose selected %s'), [field_name]),
'id', field_id + '_add',
'class', 'selector-add'
);
const remove_button = quickElement(
'button',
quickElement('li', selector_chooser),
interpolate(gettext('Remove selected chosen %s'), [field_name]),
'id', field_id + '_remove',
'class', 'selector-remove'
);
// <div class="selector-chosen">
const selector_chosen = quickElement('div', selector_div, '', 'id', field_id + '_selector_chosen');
@ -100,11 +131,19 @@ Requires core.js and SelectBox.js.
selector_chosen_title.className = 'selector-chosen-title';
selector_chosen_title.id = field_id + '_to_title';
quickElement('label', selector_chosen_title, interpolate(gettext('Chosen %s') + ' ', [field_name]), 'for', field_id + '_to');
const selector_chosen_title = quickElement('div', selector_chosen);
selector_chosen_title.className = 'selector-chosen-title';
selector_chosen_title.id = field_id + '_to_title';
quickElement('label', selector_chosen_title, interpolate(gettext('Chosen %s') + ' ', [field_name]), 'for', field_id + '_to');
quickElement(
'p',
selector_chosen_title,
interpolate(gettext('Remove %s by selecting them and then select the "Remove" arrow button.'), [field_name]),
'class', 'helptext'
'p',
selector_chosen_title,
interpolate(gettext('Remove %s by selecting them and then select the "Remove" arrow button.'), [field_name]),
'class', 'helptext'
);
const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected');
@ -116,6 +155,7 @@ Requires core.js and SelectBox.js.
'span', search_filter_selected_label, '',
'class', 'help-tooltip search-label-icon',
'aria-label', interpolate(gettext("Type into this box to filter down the list of selected %s."), [field_name])
'aria-label', interpolate(gettext("Type into this box to filter down the list of selected %s."), [field_name])
);
filter_selected_p.appendChild(document.createTextNode(' '));
@ -123,6 +163,17 @@ Requires core.js and SelectBox.js.
const filter_selected_input = quickElement('input', filter_selected_p, '', 'type', 'text', 'placeholder', gettext("Filter"));
filter_selected_input.id = field_id + '_selected_input';
quickElement(
'select',
selector_chosen,
'',
'id', field_id + '_to',
'multiple', '',
'size', from_box.size,
'name', from_box.name,
'aria-labelledby', field_id + '_to_title',
'class', 'filtered'
);
quickElement(
'select',
selector_chosen,
@ -144,6 +195,13 @@ Requires core.js and SelectBox.js.
'id', field_id + '_remove_all',
'class', 'selector-clearall'
);
const clear_all = quickElement(
'button',
selector_chosen,
interpolate(gettext('Remove all %s'), [field_name]),
'id', field_id + '_remove_all',
'class', 'selector-clearall'
);
from_box.name = from_box.name + '_old';
@ -160,16 +218,18 @@ Requires core.js and SelectBox.js.
choose_all.addEventListener('click', function(e) {
move_selection(e, this, SelectBox.move_all, field_id + '_from', field_id + '_to');
});
add_button.addEventListener('click', function(e) {
add_button.addEventListener('click', function(e) {
move_selection(e, this, SelectBox.move, field_id + '_from', field_id + '_to');
});
remove_button.addEventListener('click', function(e) {
remove_button.addEventListener('click', function(e) {
move_selection(e, this, SelectBox.move, field_id + '_to', field_id + '_from');
});
clear_all.addEventListener('click', function(e) {
move_selection(e, this, SelectBox.move_all, field_id + '_to', field_id + '_from');
});
warning_footer.addEventListener('click', function(e) {
warning_footer.addEventListener('click', function() {
filter_selected_input.value = '';
SelectBox.filter(field_id + '_to', '');
SelectFilter.refresh_filtered_warning(field_id);
@ -248,12 +308,31 @@ Requires core.js and SelectBox.js.
refresh_icons: function(field_id) {
const from = document.getElementById(field_id + '_from');
const to = document.getElementById(field_id + '_to');
// Active if at least one item is selected
document.getElementById(field_id + '_add').classList.toggle('active', SelectFilter.any_selected(from));
document.getElementById(field_id + '_remove').classList.toggle('active', SelectFilter.any_selected(to));
// Active if the corresponding box isn't empty
document.getElementById(field_id + '_add_all').classList.toggle('active', from.querySelector('option'));
document.getElementById(field_id + '_remove_all').classList.toggle('active', to.querySelector('option'));
if (!from || !to) {
// If required elements are missing, skip refreshing icons.
console.warn(`Skipping icon refresh for field_id: ${field_id}. Elements are missing.`);
return;
}
const addButton = document.getElementById(field_id + '_add');
const removeButton = document.getElementById(field_id + '_remove');
const addAllButton = document.getElementById(field_id + '_add_all');
const removeAllButton = document.getElementById(field_id + '_remove_all');
if (addButton) {
addButton.classList.toggle('active', SelectFilter.any_selected(from));
}
if (removeButton) {
removeButton.classList.toggle('active', SelectFilter.any_selected(to));
}
if (addAllButton) {
addAllButton.classList.toggle('active', from.querySelector('option'));
}
if (removeAllButton) {
removeAllButton.classList.toggle('active', to.querySelector('option'));
}
SelectFilter.refresh_filtered_warning(field_id);
},
filter_key_press: function(event, field_id, source, target) {
@ -299,10 +378,26 @@ Requires core.js and SelectBox.js.
}
};
window.addEventListener('load', function(e) {
window.addEventListener('load', function() {
document.querySelectorAll('select.selectfilter, select.selectfilterstacked').forEach(function(el) {
const data = el.dataset;
SelectFilter.init(el.id, data.fieldName, parseInt(data.isStacked, 10));
});
});
document.addEventListener('formset:removed', function(e) {
const inlineElement = e.target;
const field = inlineElement.querySelector('select.filtered');
if (field) {
const field_id = field.id.replace('_from', ''); // Remove '_from' suffix if present
const fromBox = document.getElementById(field_id + '_from');
const toBox = document.getElementById(field_id + '_to');
// Remove elements if present
if (fromBox) fromBox.remove();
if (toBox) toBox.remove();
console.log(`Cleaned up SelectFilter for field_id: ${field_id}`);
}
});
}

View File

@ -30,4 +30,15 @@
document.addEventListener('formset:added', (event) => {
$(event.target).find('.admin-autocomplete').djangoAdminSelect2();
});
// document.addEventListener('formset:added', function(e) {
// const formId = e.target.id; // Get the form ID
// const newField = formId.querySelector('select.selectfilter');
// if (newField) {
// const fieldName = newField.dataset.fieldName;
// const isStacked = parseInt(newField.dataset.isStacked, 10);
// SelectFilter.init(newField.id, fieldName, isStacked);
// }
// });
}

View File

@ -159,6 +159,11 @@
updateElementIndex($(forms).get(i), options.prefix, i);
$(forms.get(i)).find("*").each(updateElementCallback);
}
// Reinitialize SelectFilter widgets to ensure proper functionality
if (typeof updateSelectFilter === "function") {
updateSelectFilter();
}
};
const toggleDeleteButtonVisibility = function(inlineGroup) {
@ -169,7 +174,7 @@
}
};
$this.each(function(i) {
$this.each(function() {
$(this).not("." + options.emptyCssClass).addClass(options.formCssClass);
});
@ -271,7 +276,7 @@
// Stacked inlines ---------------------------------------------------------
$.fn.stackedFormset = function(selector, options) {
const $rows = $(this);
const updateInlineLabel = function(row) {
const updateInlineLabel = function() {
$(selector).find(".inline_label").each(function(i) {
const count = i + 1;
$(this).html($(this).html().replace(/(#\d+)/g, "#" + count));

View File

@ -38,14 +38,20 @@ class FilteredSelectMultiple(forms.SelectMultiple):
self.verbose_name = verbose_name
self.is_stacked = is_stacked
super().__init__(attrs, choices)
def get_context(self, name, value, attrs):
if name is None:
name = "None"
if attrs is None:
attrs = {}
context = super().get_context(name, value, attrs)
context["widget"]["attrs"]["class"] = "selectfilter"
widget_attrs = context["widget"]["attrs"]
widget_attrs["class"] = "selectfilter"
if self.is_stacked:
context["widget"]["attrs"]["class"] += "stacked"
context["widget"]["attrs"]["data-field-name"] = self.verbose_name
context["widget"]["attrs"]["data-is-stacked"] = int(self.is_stacked)
widget_attrs["class"] += "stacked"
widget_attrs["data-field-name"] = self.verbose_name
widget_attrs["data-is-stacked"] = int(self.is_stacked)
widget_attrs["id"] = attrs.get("id", f"id_{name}") # Ensure 'id' is set
return context

View File

@ -1,63 +1,17 @@
import globals from "globals";
import js from "@eslint/js";
import pluginJs from "@eslint/js";
/** @type {import('eslint').Linter.Config[]} */
export default [
js.configs.recommended,
{
files: ["**/*.js"],
rules: {
"camelcase": ["off", {"properties": "always"}],
"comma-spacing": ["error", {"before": false, "after": true}],
"curly": ["error", "all"],
"dot-notation": ["error", {"allowKeywords": true}],
"eqeqeq": ["error"],
"indent": ["error", 4],
"key-spacing": ["error", {"beforeColon": false, "afterColon": true}],
"linebreak-style": ["error", "unix"],
"new-cap": ["off", {"newIsCap": true, "capIsNew": true}],
"no-alert": ["off"],
"no-eval": ["error"],
"no-extend-native": ["error", {"exceptions": ["Date", "String"]}],
"no-multi-spaces": ["error"],
"no-octal-escape": ["error"],
"no-script-url": ["error"],
"no-shadow": ["error", {"hoist": "functions"}],
"no-underscore-dangle": ["error"],
"no-unused-vars": ["error", {"vars": "local", "args": "none"}],
"no-var": ["error"],
"prefer-const": ["error"],
"quotes": ["off", "single"],
"semi": ["error", "always"],
"space-before-blocks": ["error", "always"],
"space-before-function-paren": ["error", {"anonymous": "never", "named": "never"}],
"space-infix-ops": ["error", {"int32Hint": false}],
"strict": ["error", "global"]
},
languageOptions: {
ecmaVersion: 6,
sourceType: "script",
globals: {
...globals.browser,
...globals.commonjs,
"django": false
}
}
// Include browser globals (e.g., window, document) and node globals if needed
{
languageOptions: {
globals: {
...globals.browser, // Adds browser-specific globals like window, document
django: "readonly", // Declares django as a global variable
updateSelectFilter: "readonly", // Declares updateSelectFilter as a global variable
},
},
{
files: ["**/*.mjs"],
languageOptions: {
sourceType: "module"
}
},
{
ignores: [
"**/*.min.js",
"**/vendor/**/*.js",
"django/contrib/gis/templates/**/*.js",
"django/views/templates/*.js",
"docs/_build/**/*.js",
"node_modules/**.js",
"tests/**/*.js",
]
}
},
pluginJs.configs.recommended, // Use recommended JavaScript rules
];

View File

@ -164,3 +164,56 @@ QUnit.test('deselecting option', function(assert) {
done_left();
});
});
QUnit.test('Reinitializes SelectFilter on formset:removed', function (assert) {
const $ = django.jQuery;
// Create inline formset and append it to the fixture
const container = $('<div id="formset-container"></div>').appendTo('#qunit-fixture');
$('<select id="id_test_select_from" class="filtered"></select>').appendTo(container);
$('<select id="id_test_select_to"></select>').appendTo(container);
// Initialize SelectFilter
SelectFilter.init('id_test_select', 'Test Items', 0);
// Simulate form deletion
const event = new Event('formset:removed', { bubbles: true });
container[0].dispatchEvent(event);
// Check if SelectFilter is reinitialized
assert.ok(
$('#id_test_select_from').length > 0,
'The "from" select box exists after reinitialization'
);
assert.ok(
$('#id_test_select_to').length > 0,
'The "to" select box exists after reinitialization'
);
});
QUnit.test('Initializes SelectFilter on formset:added', function (assert) {
const $ = django.jQuery;
// Create inline formset and append it to the fixture
const container = $('<div id="formset-container"></div>').appendTo('#qunit-fixture');
const form = $('<div class="dynamic-form"></div>').appendTo(container);
$('<select id="id_new_select_from" class="filtered"></select>').appendTo(form);
$('<select id="id_new_select_to"></select>').appendTo(form);
// Simulate form addition
const event = new Event('formset:added', { bubbles: true });
form[0].dispatchEvent(event);
// Initialize SelectFilter for the new select box
SelectFilter.init('id_new_select', 'New Test Items', 0);
// Check if SelectFilter is initialized
assert.ok(
$('#id_new_select_from').length > 0,
'The "from" select box exists after initialization'
);
assert.ok(
$('#id_new_select_to').length > 0,
'The "to" select box exists after initialization'
);
});