-
Notifications
You must be signed in to change notification settings - Fork 1
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
Functionality for adding feast manually via modal as of #50 #57
base: main
Are you sure you want to change the base?
Changes from all commits
14cd053
70d8b64
ad5a4e2
ff35b98
cc4c584
3a28586
06cca81
422c502
51747db
17e3ad1
1f7ff2a
5c307fb
7ee5e41
ae2fea9
231d7f0
7c5df87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,8 @@ | |
import views | ||
from utils import logger | ||
|
||
from flask_wtf.csrf import CSRFProtect | ||
|
||
load_dotenv() | ||
|
||
|
||
|
@@ -54,6 +56,7 @@ def create_app(pypew: Optional[PyPew] = None, **kwargs) -> Flask: | |
app.add_url_rule('/feast/api/<slug>', 'feast_detail_api', views.feast_detail_api) | ||
app.add_url_rule('/feast/api/<slug>/date', 'feast_date_api', views.feast_date_api) | ||
app.add_url_rule('/feast/<slug>/docx', 'feast_docx_view', views.feast_docx_view) | ||
app.add_url_rule('/pewSheet/feastCreation', 'create_feast', views.create_feast, methods=['GET']) | ||
app.add_url_rule('/pewSheet', 'pew_sheet_create_view', views.pew_sheet_create_view, methods=['GET']) | ||
app.add_url_rule('/pewSheet/docx', 'pew_sheet_docx_view', views.pew_sheet_docx_view, methods=['GET']) | ||
app.add_url_rule('/pewSheet/clearHistory', | ||
|
@@ -101,6 +104,7 @@ def main(argv: Optional[Sequence[str]] = None) -> None: | |
|
||
pypew = PyPew() | ||
app = create_app(pypew) | ||
csrf = CSRFProtect(app) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice |
||
|
||
if args.debug: | ||
# noinspection FlaskDebugMode | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<form method="get" id="createFeastForm" action="{{ url_for('create_feast') }}"> | ||
{{ feastForm.csrf_token }} | ||
{% for field in feastFormFields %} | ||
<div class="row"> | ||
<div class="col-sm-3"> | ||
{{ feastForm[field].label(class='col-form-label') }} | ||
</div> | ||
<div class="col-sm-9"> | ||
{{ feastForm[field](class='form-control', id='feast-' + field) }} | ||
{% if feastForm[field].errors %} | ||
{% for error in feastForm[field].errors %} | ||
<small class="font-small text-danger"> | ||
{{ error }} | ||
</small> | ||
{% endfor %} | ||
{% endif %} | ||
</div> | ||
</div> | ||
{% endfor %} | ||
<div> | ||
<button id="cancel" type="reset">Cancel</button> | ||
<input id="create-feast" type="submit" value="Create Feast"> | ||
</div> | ||
</form> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
<dialog id="feast-dialog"> | ||
{% include "createFeast.html" %} | ||
</dialog> | ||
<form action="{{ url_for('pew_sheet_create_view') }}" | ||
class="px-5"> | ||
<div class="row mb-3"> | ||
|
@@ -32,7 +35,7 @@ <h3 id="titleH3"></h3> | |
<div class="row mb-3"> | ||
{{ form.secondary_feasts.label(class='col-sm-2 col-form-label') }} | ||
<div class="col-sm-5"> | ||
{{ form.secondary_feasts(class='form-select') }} | ||
{{ form.secondary_feasts(class='form-select', formnovalidate=True) }} | ||
{% if form.secondary_feasts.errors %} | ||
{% for error in form.secondary_feasts.errors %} | ||
<small class="font-small text-danger"> | ||
|
@@ -41,9 +44,11 @@ <h3 id="titleH3"></h3> | |
{% endfor %} | ||
{% endif %} | ||
</div> | ||
<div class="col-sm-3"> | ||
<button id="add-feast-dialog" type="button">Add Feast</button> | ||
</div> | ||
</div> | ||
|
||
|
||
<div class="row mb-3"> | ||
{{ form.date.label(class='col-sm-1 col-form-label') }} | ||
<div class="col"> | ||
|
@@ -183,3 +188,136 @@ <h3 id="titleH3"></h3> | |
</form> | ||
|
||
<script src="{{ url_for('static', filename='serviceForm.js') }}"></script> | ||
<script> | ||
|
||
// Note: logic needs to be able to access python API and hence was placed here | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, all you're doing is injecting the You could hardcode the URL, but maybe a better way to pass data from the Jinja2 backend to the JS would be something like <input id="myUrl" type="hidden" value="{{ url_for(...) }}">
<script> // put this in a separate file
const myUrl = document.getElementById("myUrl").value;
</script> You could alternatively use the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, thanks. I've seen something similar in the pewSheet.html, which then would need fixing as well? What do you mean by the data-... attributes? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
e.g. <p id="foo" data-url="{{ url_for(...) }}"></p>
<script>
const myUrl = document.getElementById("foo").dataset.url
</script> |
||
var feastsArray = []; | ||
var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]; | ||
// source: https://www.freecodecamp.org/news/format-dates-with-ordinal-number-suffixes-javascript/ | ||
const nthNumber = (number) => { | ||
if (number > 3 && number < 21) return "th"; | ||
switch (number % 10) { | ||
case 1: | ||
return "st"; | ||
case 2: | ||
return "nd"; | ||
case 3: | ||
return "rd"; | ||
default: | ||
return "th"; | ||
} | ||
}; | ||
var feastName = document.getElementById("feast-name"); | ||
var feastDay = document.getElementById("feast-day"); | ||
var feastMonth = document.getElementById("feast-month"); | ||
feastName.addEventListener('change', checkForNameDuplicates); | ||
feastDay.addEventListener('change', checkForDateDuplicates); | ||
feastMonth.addEventListener('change', checkForDateDuplicates); | ||
|
||
function checkForDateDuplicates() { | ||
var day = feastDay.value? parseInt(feastDay.value) : 0; | ||
var month = feastMonth.value? parseInt(feastMonth.value): 0; | ||
if(day == 0 || month == 0){ | ||
return; | ||
} | ||
console.log(nthNumber(day) + ', ' + monthNames[month-1]); | ||
var similarityDetected = false; | ||
feastsArray.every(function (el) { | ||
// compare date of feast to input month and day | ||
var dateComponents = el.next.split(' '); | ||
if(dateComponents.length == 4 && (day + nthNumber(day) == dateComponents[1]) && monthNames[month-1] == dateComponents[2]){ | ||
similarityDetected = true; | ||
return false; | ||
} | ||
|
||
return true; | ||
}); | ||
|
||
if (similarityDetected) { | ||
alert("You're creating a feast for " + day + "." + month + "., but there already exists a feast on this date; are you accidentally creating a duplicate?"); | ||
} | ||
} | ||
|
||
function checkForNameDuplicates() { | ||
var input = feastName.value; | ||
var words = input.split(' '); | ||
var similarityCt = 0, similarFeast = ''; | ||
feastsArray.every(function (el) { | ||
if (similarityCt > 1) { | ||
return false; | ||
} | ||
similarityCt = 0; | ||
words.every(function (word) { | ||
if (similarityCt > 1) { | ||
return false; | ||
} | ||
if (el.name.includes(word)) { | ||
if (word != 'and') { | ||
similarityCt++; | ||
} | ||
if(similarityCt == 2){ | ||
similarFeast = el.name; | ||
} | ||
} | ||
return true; | ||
}); | ||
return true; | ||
}); | ||
|
||
if (similarityCt > 1) { | ||
alert("You're inputting " + input + ", but " + similarFeast + " already exists; are you accidentally creating a duplicate?"); | ||
} | ||
} | ||
|
||
const dialog = document.getElementById("feast-dialog"); | ||
const addFeastBtn = document.getElementById('add-feast-dialog'); | ||
addFeastBtn.onclick = () => { | ||
dialog.showModal(); | ||
}; | ||
|
||
const cancelButton = document.getElementById("cancel"); | ||
cancelButton.onclick = () => { | ||
dialog.close("Feast creation cancelled"); | ||
}; | ||
|
||
function updateFeasts(){ | ||
// refresh feasts | ||
console.log('retrieved data from database'); | ||
const feastsApiUrl = "{{ url_for('feast_upcoming_api') }}"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see note above |
||
fetch(feastsApiUrl).then(response => response.json()) | ||
.then(function(response) { | ||
// clear choice options | ||
var secondaryFeastsField = document.getElementById('secondary_feasts'); | ||
secondaryFeastsField.replaceChildren(); | ||
// recreate choice options | ||
response.forEach(element => { | ||
var opt = document.createElement('option'); | ||
opt.text = element.name; | ||
opt.value = element.slug; | ||
secondaryFeastsField.add(opt); | ||
}); | ||
feastsArray = response; | ||
}); | ||
} | ||
|
||
const createFeastBtn = document.getElementById("create-feast"); | ||
createFeastBtn.onclick = () => { | ||
try { | ||
dialog.close("Feast creation request submitted!"); | ||
// wait some time for database update | ||
const myTimeout = setTimeout(updateFeasts, 2000); | ||
} catch (error) { | ||
dialog.close("Feast creation aborted due to errors!"); | ||
} | ||
}; | ||
|
||
dialog.addEventListener('close', function (e) { | ||
e.preventDefault(); | ||
console.log(dialog.returnValue); | ||
}); | ||
|
||
// load secondary feast options on init | ||
(() => { | ||
updateFeasts(); | ||
})(); | ||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no validation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the newly added feast is selected from the dropdown, 'Not a valid choice' is displaying. The workaround to this is no validation, see pallets-eco/wtforms#434.