Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add DateTimeRange input/picker/calendar #94

Merged
merged 62 commits into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
12a9b28
add validation messages for date fields with min/max-constraints
jrief Aug 6, 2023
b64cf99
refactor date(time)-pickers to use contenteditable="true"
jrief Aug 6, 2023
3b32240
use proper mark to signal style pilfering
jrief Aug 6, 2023
20d4b15
remove misleading docstring
jrief Aug 6, 2023
553f617
make calendar icon smaller
jrief Aug 6, 2023
fc851a9
fix failing unit tests
jrief Aug 6, 2023
cc5943d
rename CSS classes according to standard
jrief Aug 7, 2023
ad3d641
refactored Calendar out from DateTimePicker
jrief Aug 10, 2023
b2a0760
WiP on date-ranger picker
jrief Aug 10, 2023
e1b61a9
attribute role not given for element
jrief Aug 10, 2023
8f28f34
increase sleeping time
jrief Aug 10, 2023
70efc1d
fix documentation
jrief Aug 10, 2023
1d92c93
handle styles of Calendar and DatePicker separately
jrief Aug 15, 2023
1b9bad7
remove legacy docstrings
jrief Aug 15, 2023
fd0cb97
use JavaScript properties for certain functions
jrief Aug 17, 2023
1204b9b
change signature of FieldErorMessages
jrief Aug 17, 2023
effe9f9
remove RangeInput.ts from project
jrief Aug 17, 2023
696ced6
Refactor Widget and FieldErrorMessages into own module
jrief Aug 18, 2023
cf70277
do not abuse custom_error for required message of Selectize widget
jrief Aug 22, 2023
368e216
MVP of date(time)-range-picker
jrief Aug 26, 2023
350815a
add rubric for form_collection_valid
jrief Aug 26, 2023
33b96ba
fix faling e2e tests
jrief Aug 26, 2023
c1fec21
working hover effect in datetime ranges with interval
jrief Sep 1, 2023
c662192
rename preselected -> constricted
jrief Sep 2, 2023
3f8e29c
fix selected ranges display
jrief Sep 2, 2023
632b60d
prevent loading same styles multiple times
jrief Sep 5, 2023
0c7da47
fully functional datetime-range-picker
jrief Sep 5, 2023
06cc0db
fix indention
jrief Sep 5, 2023
9452513
fix all in-between datetime markers
jrief Sep 6, 2023
5d98655
prevent loading same styles multiple times
jrief Sep 6, 2023
edfc074
optionally render Calendar in 12 hour mode
jrief Sep 7, 2023
d9c8463
fix min/max-date in datetime range picker
jrief Sep 7, 2023
5547b67
fix margins in datetime field
jrief Sep 7, 2023
0252c2c
add webcomponents django-datefield and django-datetimefield
jrief Sep 11, 2023
0408dbc
fully working date(time)range fields
jrief Sep 15, 2023
a51faa7
furo supports json builds again
jrief Sep 15, 2023
877f7b3
STATIC_ROOT never used
jrief Sep 15, 2023
be0323f
fix typos in documentation
jrief Sep 23, 2023
542348d
do not perform tests when changing docs
jrief Sep 23, 2023
db1f8e2
use ManifestStaticFilesStorage to avoid delivering expired files
jrief Sep 23, 2023
762f470
Merge branch 'main' into range-input
jrief Sep 23, 2023
f38bdf0
render pure range Calendar highlighting start- and end-date
jrief Sep 26, 2023
ccc66b2
set initial dates in testapp
jrief Sep 26, 2023
cb4f32a
separate requirements to build docs
jrief Sep 26, 2023
93b2f7d
fix #87 : type in testapp
jrief Sep 26, 2023
f7d2342
make project Django-5.0 ready
jrief Sep 26, 2023
29abb14
show nearest date in aside elements
jrief Sep 30, 2023
3ab0937
mention all six date-time widgets in documentation
jrief Sep 30, 2023
4c6b619
special today SVG icon
jrief Sep 30, 2023
7e310e0
adopt moon layout to new template
jrief Sep 30, 2023
c37200a
remove useless code
jrief Oct 12, 2023
ac5cb71
Upgrade to nodejs version 18
jrief Oct 13, 2023
dcdf82f
Complete documentation on datetime range
jrief Oct 17, 2023
5861330
role="group" with no display setting
jrief Oct 17, 2023
d1e2fc6
fix all unit tests to work with changed interface
jrief Oct 17, 2023
876efa3
adopt to Django 5
jrief Oct 17, 2023
246ab24
choices may be of type CallableChoiceIterator
jrief Oct 17, 2023
a001b4d
prevent click on disabled cells
jrief Oct 19, 2023
aab3d62
background color for hover
jrief Oct 19, 2023
a753a5b
add tests for date range calendar
jrief Oct 19, 2023
33f0ca9
improve documentation on date range
jrief Oct 19, 2023
dc0da05
Bump to version 1.2
jrief Oct 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .deployment/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ WORKDIR /web
# install packages outside of PyPI
RUN apt-get upgrade -y
RUN apt-get install -y curl make
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash -
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -
RUN apt-get install -y nodejs npm
RUN pip install --upgrade pip

Expand All @@ -16,9 +16,8 @@ COPY package-lock.json /web/package-lock.json
RUN npm ci

# install Python specific requirements
RUN pip install django psycopg2-binary Pillow uWSGI docutils Sphinx sphinx-toolbox
RUN pip install django psycopg2-binary Pillow uWSGI docutils Sphinx sphinx-toolbox furo
RUN pip install https://github.com/jrief/django-sphinx-view/archive/refs/heads/main.zip
RUN pip install https://github.com/jrief/furo/archive/refs/heads/json-build.zip

# copy project relevant files into container
ADD assets /web/assets
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ on:
push:
branches:
- main
- version_1
paths-ignore:
- '**.md'
- '**.rst'
- '/docs/**'
pull_request:
branches:
- main
- version_1
paths-ignore:
- '**.md'
- '**.rst'
- '/docs/**'

jobs:
build:
Expand All @@ -23,10 +23,10 @@ jobs:
matrix:
python-version: ["3.9", "3.10", "3.11"]
django-version: ["4.1.*", "4.2.*"]
node-version: ["16.x"]
node-version: ["18.x"]
include:
- build-client: "esbuild"
- build-client: "rollup"
- build-client: "esbuild" # rollup is not working in NodeJS 18
python-version: "3.10"
django-version: "4.1.*"

Expand Down
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
## Changes

1.2
* Add widgets `DatePicker`, `DateTextbox`, `DateCalendar`, `DateTimePicker`, `DateTimeTextbox`
and `DateTimeCalendar`. They can be used as alternative widgets to Django's `DateInput` and
`DateTimeInput` widgets.
* Add range fields `DateRangeField` and `DateTimeRangeField` which can be used in forms to query
for a date- or datetime range. With these two fields six more widgets are added to the library:
`DateRangeCalendar`, `DateRangeTextbox`, `DateRangePicker`, `DateTimeRangeCalendar`,
`DateTimeRangeTextbox` and `DateTimeRangePicker`.
* The calendar widget now supports 12 hours time format.
* Fix: In rare occasions, the styling of widgets has been loaded twice.
* Fix: Field choices declared as callables are now supported.
* Prepared rendering for Django-5.0.

- 1.1.2
* Drop support for Django-4.0.

Expand All @@ -9,7 +22,7 @@

- 1.1
* Form collections containing only empty fields won't be submitted. This applies to collections
added using `extra_siblings` as to collections added using the appropriate button.
added using `extra_siblings` as to collections added using the appropriate "Add <label>" button.
* Fix problem when using MultiWidget widgets. Under some configurations an error was raised
stating “Duplicate name 'xxx' on multiple input fields”.

Expand Down
28 changes: 24 additions & 4 deletions client/django-formset.monolith.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import {StyleHelpers} from './django-formset/helpers';
// remember to always reflect imports below here also in django-formset.ts
import {DjangoSelectizeElement} from './django-formset/DjangoSelectize';
import {SortableSelectElement} from './django-formset/SortableSelect';
import {DualSelectorElement} from "./django-formset/DualSelector";
import {RichTextAreaElement} from "./django-formset/RichtextArea";
import {DjangoSlugElement} from "./django-formset/DjangoSlug";
import {DatePickerElement, DateTimePickerElement} from "./django-formset/DateTimePicker";
import {DualSelectorElement} from './django-formset/DualSelector';
import {RichTextAreaElement} from './django-formset/RichtextArea';
import {DjangoSlugElement} from './django-formset/DjangoSlug';
import {DateFieldElement, DatePickerElement, DateTimeFieldElement, DateTimePickerElement} from './django-formset/DateTime';


window.addEventListener('DOMContentLoaded', (event) => {
Expand All @@ -25,10 +25,30 @@ window.addEventListener('DOMContentLoaded', (event) => {
customElementNames.push('django-richtext');
window.customElements.define('django-slug', DjangoSlugElement, {extends: 'input'});
customElementNames.push('django-slug');
window.customElements.define('django-datefield', DateFieldElement, {extends: 'input'});
customElementNames.push('django-datefield');
window.customElements.define('django-datecalendar', DateFieldElement, {extends: 'input'});
customElementNames.push('django-datecalendar');
window.customElements.define('django-datepicker', DatePickerElement, {extends: 'input'});
customElementNames.push('django-datepicker');
window.customElements.define('django-datetimefield', DateTimeFieldElement, {extends: 'input'});
customElementNames.push('django-datetimefield');
window.customElements.define('django-datetimecalendar', DateFieldElement, {extends: 'input'});
customElementNames.push('django-datetimecalendar');
window.customElements.define('django-datetimepicker', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-datetimepicker');
window.customElements.define('django-daterangefield', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-daterangefield');
window.customElements.define('django-daterangecalendar', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-daterangecalendar');
window.customElements.define('django-daterangepicker', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-daterangepicker');
window.customElements.define('django-datetimerangefield', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-datetimerangefield');
window.customElements.define('django-datetimerangecalendar', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-datetimerangecalendar');
window.customElements.define('django-datetimerangepicker', DateTimePickerElement, {extends: 'input'});
customElementNames.push('django-datetimerangepicker');

const foundIds = new Set<string>();
document.querySelectorAll('django-formset [id]').forEach(element => {
Expand Down
74 changes: 72 additions & 2 deletions client/django-formset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,90 @@ window.addEventListener('DOMContentLoaded', (event) => {
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datefield"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTime').then(({DateFieldElement}) => {
defineComponent(resolve, 'django-datefield', DateFieldElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datecalendar"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/Calendar').then(({DateCalendarElement}) => {
defineComponent(resolve, 'django-datecalendar', DateCalendarElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datepicker"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTimePicker').then(({DatePickerElement}) => {
import('./django-formset/DateTime').then(({DatePickerElement}) => {
defineComponent(resolve, 'django-datepicker', DatePickerElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datetimefield"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTime').then(({DateTimeFieldElement}) => {
defineComponent(resolve, 'django-datetimefield', DateTimeFieldElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datetimecalendar"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/Calendar').then(({DateCalendarElement}) => {
defineComponent(resolve, 'django-datetimecalendar', DateCalendarElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datetimepicker"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTimePicker').then(({DateTimePickerElement}) => {
import('./django-formset/DateTime').then(({DateTimePickerElement}) => {
defineComponent(resolve, 'django-datetimepicker', DateTimePickerElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-daterangefield"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTime').then(({DateRangeFieldElement}) => {
defineComponent(resolve, 'django-daterangefield', DateRangeFieldElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-daterangecalendar"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/Calendar').then(({DateCalendarElement}) => {
defineComponent(resolve, 'django-daterangecalendar', DateCalendarElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-daterangepicker"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTime').then(({DateRangePickerElement}) => {
defineComponent(resolve, 'django-daterangepicker', DateRangePickerElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datetimerangefield"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTime').then(({DateTimeRangeFieldElement}) => {
defineComponent(resolve, 'django-datetimerangefield', DateTimeRangeFieldElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datetimerangecalendar"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/Calendar').then(({DateCalendarElement}) => {
defineComponent(resolve, 'django-datetimerangecalendar', DateCalendarElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
if (fragmentRoot.querySelector('input[is="django-datetimerangepicker"]')) {
promises.push(new Promise((resolve, reject) => {
import('./django-formset/DateTime').then(({DateTimeRangePickerElement}) => {
defineComponent(resolve, 'django-datetimerangepicker', DateTimeRangePickerElement, {extends: 'input'});
}).catch(err => reject(err));
}));
}
}

document.querySelectorAll('template.empty-collection').forEach(element => {
Expand Down
Loading
Loading