diff --git a/package.json b/package.json
index c273bc834..21c6ec39f 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
},
"homepage": "https://github.com/wger-project/wger",
"dependencies": {
+ "htmx.org": "^2.0.3",
"bootstrap": "5.3.3",
"components-font-awesome": "5.9.0",
"datatables.net-bs5": "^2.1.8",
diff --git a/wger/__init__.py b/wger/__init__.py
index 1b7c47e90..67e1eade4 100644
--- a/wger/__init__.py
+++ b/wger/__init__.py
@@ -8,10 +8,9 @@
# Local
from .celery_configuration import app
-
MIN_APP_VERSION = (1, 7, 4, 'final', 1)
-VERSION = (2, 3, 0, 'alpha', 2)
+VERSION = (2, 3, 0, 'alpha', 3)
RELEASE = True
diff --git a/wger/core/static/js/wger-core.js b/wger/core/static/js/wger-core.js
index 877f01d70..d6daf501a 100644
--- a/wger/core/static/js/wger-core.js
+++ b/wger/core/static/js/wger-core.js
@@ -15,44 +15,6 @@
*/
'use strict';
-/*
- AJAX related functions
-
- See https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax for
- more information
- */
-function getCookie(name) {
- var cookie;
- var cookies;
- var cookieValue = null;
- var loopCounter;
- if (document.cookie && document.cookie !== '') {
- cookies = document.cookie.split(';');
- for (loopCounter = 0; loopCounter < cookies.length; loopCounter++) {
- cookie = jQuery.trim(cookies[loopCounter]);
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) === (name + '=')) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
- }
- }
- }
- return cookieValue;
-}
-
-function csrfSafeMethod(method) {
- // These HTTP methods do not require CSRF protection
- return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
-}
-
-$.ajaxSetup({
- crossDomain: false, // obviates need for sameOrigin test
- beforeSend: function (xhr, settings) {
- if (!csrfSafeMethod(settings.type)) {
- xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'));
- }
- }
-});
function getCurrentLanguage() {
// Returns a short name, like 'en' or 'de'
@@ -60,154 +22,6 @@ function getCurrentLanguage() {
}
-/*
- Open a modal dialog for form editing
- */
-function modalDialogFormEdit() {
- var $submit;
- var $form;
- $form = $('#ajax-info-content').find('form');
- $submit = $($form).find('#form-save');
-
- $submit.click(function (e) {
- var formData;
- var formAction;
- e.preventDefault();
- formAction = $form.attr('action');
- formData = $form.serialize();
-
- // Unbind all click elements, so the form doesn't get submitted twice
- // if the user clicks 2 times on the button (while there is already a request
- // happening in the background)
- $submit.off();
-
- // Show a loader while we fetch the real page
- $form.html('
' +
- ' ' +
- '
');
- $('#ajax-info-title').html('Processing'); // TODO: translate this
-
- // OK, we did the POST, what do we do with the result?
- $.ajax({
- type: 'POST',
- url: formAction,
- data: formData,
- beforeSend: function (jqXHR) {
- // Send a custom header so django's messages are not displayed in the next
- // request which will be not be displayed to the user, but on the next one
- // that will
- jqXHR.setRequestHeader('X-wger-no-messages', '1');
- },
- success: function (data, textStatus, jqXHR) {
- var url = jqXHR.getResponseHeader('X-wger-redirect');
- if (url) {
- window.location.href = url;
- /*
- if(document.URL.indexOf(url)) {
- history.pushState({}, "", url);
- }
- */
- } else if ($(data).find('form .has-error').length > 0) {
- // we must do the same with the new form as before, binding the click-event,
- // checking for errors etc, so it calls itself here again.
- $form.html($(data).find('form').html());
- $('#ajax-info-title').html($(data).find('#page-title').html());
- modalDialogFormEdit();
- } else {
- console.log('No X-wger-redirect found but also no .has-error!');
- $('#wger-ajax-info').modal('hide');
- $form.html(data);
- }
-
- // Call other custom initialisation functions
- // (e.g. if the form as an autocompleter, it has to be initialised again)
- if (typeof wgerCustomModalInit !== 'undefined') {
- wgerCustomModalInit(); // eslint-disable-line no-undef
- }
-
- if (typeof wgerCustomPageInit !== 'undefined') {
- wgerCustomPageInit(); // eslint-disable-line no-undef
- }
- },
- error: function (jqXHR) {
- // console.log(errorThrown); // INTERNAL SERVER ERROR
- $('#ajax-info-content').html(jqXHR.responseText);
- }
- });
- });
-}
-
-function wgerFormModalDialog() {
- var $wgerModalDialog;
- $wgerModalDialog = $('.wger-modal-dialog');
- // Unbind all other click events so we don't do this more than once
- $wgerModalDialog.off();
-
- // Load the edit dialog when the user clicks on an edit link
- $wgerModalDialog.click(function (e) {
- var $ajaxInfoContent;
- var targetUrl;
- e.preventDefault();
- targetUrl = $(this).attr('href');
-
- // It's not possible to have more than one modal open at any time, so close them
- $('.modal').modal('hide');
-
- // Show a loader while we fetch the real page
- $ajaxInfoContent = $('#ajax-info-content');
- $ajaxInfoContent.html('
' +
- ' ' +
- '
');
- $('#ajax-info-title').html('Loading...');
- $('#wger-ajax-info').modal('show');
-
- $ajaxInfoContent.load(targetUrl + ' .wger-form',
- function (responseText, textStatus, XMLHttpRequest) {
- var $ajaxInfoTitle;
- var modalTitle;
- $ajaxInfoTitle = $('#ajax-info-title');
- if (textStatus === 'error') {
- $ajaxInfoTitle.html('Sorry but an error occured');
- $('#ajax-info-content').html(XMLHttpRequest.status + ' ' + XMLHttpRequest.statusText);
- }
-
- // Call other custom initialisation functions
- // (e.g. if the form as an autocompleter, it has to be initialised again)
- if (typeof wgerCustomModalInit !== 'undefined') {
- // Function is defined in templates. Eslint doesn't check the templates resulting in a
- // un-def error message.
- wgerCustomModalInit(); // eslint-disable-line no-undef
- }
-
- // Set the new title
- modalTitle = '';
- if ($(responseText).find('#page-title').length > 0) {
- // Complete HTML page
- modalTitle = $(responseText).find('#page-title').html();
- } else {
- // Page fragment
- modalTitle = $(responseText).filter('#page-title').html();
- }
- $ajaxInfoTitle.html(modalTitle);
-
- // If there is a form in the modal dialog (there usually is) prevent the submit
- // button from submitting it and do it here with an AJAX request. If there
- // are errors (there is an element with the class 'ym-error' in the result)
- // reload the content back into the dialog so the user can correct the entries.
- // If there isn't assume all was saved correctly and load that result into the
- // page's main DIV (#main-content). All this must be done like this because there
- // doesn't seem to be any reliable and easy way to detect redirects with AJAX.
- if ($(responseText).find('.wger-form').length > 0) {
- modalDialogFormEdit();
- }
- });
- });
-}
-
/*
Returns a random hex string. This is useful, e.g. to add a unique ID to generated
HTML elements
@@ -223,8 +37,8 @@ function getRandomHex() {
Template-like function that adds form elements to the ajax exercise selection in the edit set page
*/
function addExercise(exercise) {
- var $exerciseSearchLog;
- var resultDiv;
+ let $exerciseSearchLog;
+ let resultDiv;
resultDiv = '
{% blocktranslate %}If a license has been localized, e.g. the Creative Commons
- licenses for the different countries, add them as separate entries here.{% endblocktranslate %}
- {% translate "You need to verify your email to contribute exercises" %}
+
+ {% translate "You need to verify your email to contribute exercises" %}
+
{% blocktranslate %}You can indicate how long you want to do each workout
before jumping to the next. It is also possible to create a loop, so you
- always do the same workouts in succession, e.g. A > B > C > A > B > C and so on.{% endblocktranslate %}
+ always do the same workouts in succession, e.g. A > B > C > A > B > C and so
+ on.{% endblocktranslate %}
{% blocktranslate %}The currently active schedule will remain active (and be
shown e.g. in your dashboard) till it reaches the last workout or till you
@@ -47,7 +48,6 @@
{% block options %}
-
- {% translate "Add schedule" %}
-
+ {% translate 'Add schedule' as text %}
+ {% modal_link url='manager:schedule:add' text=text %}
{% endblock %}
diff --git a/wger/manager/templates/schedule/view.html b/wger/manager/templates/schedule/view.html
index 959111422..ce80e30e2 100644
--- a/wger/manager/templates/schedule/view.html
+++ b/wger/manager/templates/schedule/view.html
@@ -65,16 +65,29 @@
{% if is_owner %}
{% translate "Export this schedule as a calendar file." %}
{% blocktranslate %}You can then import the file it into your calendar
application for example google calendar, outlook or iCal. This will create
- an appointment for each training day with the appropriate exercises.{% endblocktranslate %}
+ an appointment for each training day with the appropriate
+ exercises.{% endblocktranslate %}
{% translate "Export this workout as a calendar file." %}
{% blocktranslate %}You can then import the file it into your calendar
application for example google calendar, outlook or iCal. This will create
- an appointment for each training day with the appropriate exercises.{% endblocktranslate %}
+ an appointment for each training day with the appropriate
+ exercises.{% endblocktranslate %}