Skip to content
This repository has been archived by the owner on Mar 27, 2023. It is now read-only.

Webpack for Javascript #523

Draft
wants to merge 28 commits into
base: staging
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8895ef4
Added Webpack
maltezacharias Apr 19, 2020
3796487
switched to webpack for student profile
maltezacharias Apr 20, 2020
5a36264
Restructuring
maltezacharias Apr 24, 2020
867aa4e
Added JS linting
maltezacharias Apr 24, 2020
391d73f
Fixed indenting setting
maltezacharias Apr 25, 2020
26719e7
Auto generate bundles
maltezacharias Apr 25, 2020
d6d33c4
Added css and file support to webpack, leaflet via bundle
maltezacharias Apr 25, 2020
86c1f4b
Ignore generated bundle file
maltezacharias Apr 25, 2020
5073238
Dummy main.js
maltezacharias Apr 25, 2020
75c4d9e
Clean Up profile helper
maltezacharias Apr 25, 2020
24719ba
Removed duplicate libraries after move to webpack
maltezacharias Apr 25, 2020
b376db1
Changed minifier settings
maltezacharias Apr 25, 2020
d12d9f4
switched to webpack for student profile
maltezacharias Apr 20, 2020
0a67c07
Added JS linting
maltezacharias Apr 24, 2020
0eb5144
Added css and file support to webpack, leaflet via bundle
maltezacharias Apr 25, 2020
5f6e9a1
Ignore generated bundle file
maltezacharias Apr 25, 2020
0cf4a6e
Dummy main.js
maltezacharias Apr 25, 2020
db71bbd
Hand picked requirements
maltezacharias May 2, 2020
0ee4857
Move bootstrap dependency into frontend
maltezacharias May 21, 2020
efae999
Run linter for Malte
bjrne May 22, 2020
d541402
Recreated package-lock.json
maltezacharias May 23, 2020
b39dded
Include pre-commit hook for javascript
maltezacharias May 23, 2020
ec2871d
Removed pre-commit linting errors
maltezacharias May 23, 2020
4f26d09
pre-commit config
maltezacharias May 23, 2020
798d24e
Remove temp edit
maltezacharias May 23, 2020
0956102
Translation fixes
maltezacharias May 23, 2020
4e9e248
Merge remote-tracking branch 'origin/staging' into webpack-js
maltezacharias May 23, 2020
d0d3ff7
Fix translations
maltezacharias May 23, 2020
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,4 @@ docker-compose.yml

# Ignore all config files
*.env
frontend/webpack-stats.json
12 changes: 12 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,15 @@ repos:
^database/backups/|
^database/data/
)
- repo: https://github.com/pre-commit/mirrors-eslint
rev: 'v7.1.0' # Use the sha / tag you want to point at
hooks:
- id: eslint
additional_dependencies:
- eslint@^6.8.0
- babel-eslint@^10.1.0
files: >
(?x)(
^frontend/webpack\.config\.js|
^frontend/src/
)
56 changes: 55 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
- Copy `backend.prod.env.example` and `database.prod.env.example` to `backend.prod.env` and `database.prod.env` and fill in appropriate values
- Run `./deploy.sh` (uses Docker) and visit `http://localhost:8000/`


## Docker
### Development
- Build images and run containers
Expand Down Expand Up @@ -106,3 +105,58 @@ You can create and delete random fake students and hospitals using `manage.py cr
## Forks
Thanks for forking our repository. Pay attention that Travis CI doesn't test your code with sendgrid.
If you want to use sendgrid for your tests, add your repository name to the list in the if statement for NOT_FORK in `backend/match4healthcare/settings/production.py` and specify the `SENDGRID_API_KEY` environment variable in the Travis run settings.


## Javascript

This project uses webpack to create javascript bundles. Custom Javascript is only added to pages when it is needed to enhance default Django functionality or to create user experience improvements.

Notable examples are
- Map Views
- User Profile to hide unneeded blocks

Javascript sources are created in frontend/src folder

To build them node needs to be installed. We suggest using [Node Version Manager](https://github.com/nvm-sh/nvm) to install node. Dependencies can be installed using

```
cd frontend && npm install
```

### Build

All commands need to be executed in `./frontend`

- Build javascript bundles
`npm run build`
- Build javascript bundles in devMode and rebuilt when changes are made
`npm run dev`

### Loading bundles

To load a bundle in a django template add the following tags:
```
{% load render_bundle from webpack_loader %}
{% render_bundle 'student' %}
```

Django will then use the webpack-stats.json to determine which file from dist folder to include.
The dist folder has been added to the STATICFILES_DIRS so it will be found automatically

### Adding new bundles

When creating new bundles add an entry in `webpack.config.js` under `entry`:
```
entry: {
main: ['./src/main.js'],
....
new_bundle: ['./src/new_bundle.js'],
},
```

As a rule of thumb, new bundles should be created in the src directory, their modules should be loaded from the sub-directories. A page should only ever load one bundle. If modules are needed in several bundles, just require them

#### JQuery

JQuery is loaded as a part of the bootstrap initialization. This will be kept in the main django project codebase.
It is not necessary to load jQuery via webpack, an external reference can be used. (See [https://webpack.js.org/configuration/externals/](https://webpack.js.org/configuration/externals/))
45 changes: 4 additions & 41 deletions backend/apps/accounts/templates/student_edit.html
Original file line number Diff line number Diff line change
@@ -1,59 +1,22 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load render_bundle from webpack_loader %}

{% block title %}
{% blocktrans %}
Profil - Studierende
Profil - Helfer*innen
{% endblocktrans %}
{% endblock %}

{% block header %}
{% render_bundle 'student' %}
<link rel="stylesheet" href="{% static 'css/form.css' %}">
<script type="text/javascript">

var signUpHelper = {
handleQualificationInput : function handleQualificationInput(event) {
let sourceElement = event.srcElement;
let qualificationSelected = event.srcElement.checked;

// Extract qualification Id from parent div with suitable class, name ausbildung-checkbox-<id>
let qualificationId = event.srcElement.closest("div.ausbildung-checkbox").id.split("-").slice(-1)
this.setQualificationSectionVisibility(qualificationId, qualificationSelected)
},
setQualificationSectionVisibility : function setQualificationSectionVisibility(id, setVisibility) {
let section = document.getElementById(`div-ausbildung-${id}`)
if (!section) return;
if (setVisibility) {
section.classList.remove('hidden')
} else {
section.classList.add('hidden');
section.querySelectorAll("input[type='checkbox']").forEach( (checkbox) => { checkbox.checked = false })
section.querySelectorAll("input[type='text'], select").forEach( (textbox) => { textbox.value = '' })
}

},
}

document.addEventListener("DOMContentLoaded", function(event) {
let qualifikationSelectors = document.querySelectorAll("div.ausbildung-checkbox input")
qualifikationSelectors.forEach(element => {
element.addEventListener("change", (event) => { signUpHelper.handleQualificationInput(event) })

// To handle Mozillas brilliant idea to keep state of checkboxes on refresh, trigger dummy handler for every checkbox
signUpHelper.handleQualificationInput({ srcElement: element });
})

});

</script>
{% endblock %}

{% load crispy_forms_tags %}

{% block content %}


<div class="container">
<br>
<br>
Expand Down Expand Up @@ -122,4 +85,4 @@ <h2 class="font-weight-light match4hc-title">{% blocktrans %}Aktualisiere hier j
</div>
</div>
<br>
{% endblock %}
{% endblock %}
50 changes: 5 additions & 45 deletions backend/apps/accounts/templates/student_signup.html
Original file line number Diff line number Diff line change
@@ -1,56 +1,22 @@
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load render_bundle from webpack_loader %}

{% block title %}
{% blocktrans %}Registrierung - Freiwillige{% endblocktrans %}
{% blocktrans %}
Registrierung - Helfer*innen
{% endblocktrans %}
{% endblock %}

{% block header %}
<script type="text/javascript">

var signUpHelper = {
handleQualificationInput : function handleQualificationInput(event) {
let sourceElement = event.srcElement;
let qualificationSelected = event.srcElement.checked;

// Extract qualification Id from parent div with suitable class, name ausbildung-checkbox-<id>
let qualificationId = event.srcElement.closest("div.ausbildung-checkbox").id.split("-").slice(-1)
this.setQualificationSectionVisibility(qualificationId, qualificationSelected)
},
setQualificationSectionVisibility : function setQualificationSectionVisibility(id, setVisibility) {
let section = document.getElementById(`div-ausbildung-${id}`)
if (!section) return;
if (setVisibility) {
section.classList.remove('hidden')
} else {
section.classList.add('hidden');
section.querySelectorAll("input[type='checkbox']").forEach( (checkbox) => { checkbox.checked = false })
section.querySelectorAll("input[type='text'], select").forEach( (textbox) => { textbox.value = '' })
}

},
}

document.addEventListener("DOMContentLoaded", function(event) {
let qualifikationSelectors = document.querySelectorAll("div.ausbildung-checkbox input")
qualifikationSelectors.forEach(element => {
element.addEventListener("change", (event) => { signUpHelper.handleQualificationInput(event) })

// To handle Mozillas brilliant idea to keep state of checkboxes on refresh, trigger dummy handler for every checkbox
signUpHelper.handleQualificationInput({ srcElement: element });
})

});

</script>
{% render_bundle 'student' %}
<link rel="stylesheet" href="{% static 'css/form.css' %}">
{% endblock %}

{% load crispy_forms_tags %}

{% block content %}

<div class="container">
<div style="height:40px"></div>
{% if user.is_authenticated %}
Expand Down Expand Up @@ -87,10 +53,4 @@ <h2 class="font-weight-light match4hc-title">{% blocktrans %}Wir verbinden Helfe
</div>
</div>

<script type="text/javascript">
$( document ).ready(function() {
$("#id_availability_start").attr("type", "date");
});
</script>

{% endblock %}
52 changes: 25 additions & 27 deletions backend/apps/mapview/templates/mapview/map.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,37 +8,35 @@
{% endblock %}

{% block header %}
<link rel="stylesheet" href="{% static 'js/leaflet-1.6.0/leaflet.css' %}" />
<link rel="stylesheet" href="{% static 'js/leaflet.markercluster-1.4.1/MarkerCluster.css' %}" />
<link rel="stylesheet" href="{% static 'js/leaflet.markercluster-1.4.1/MarkerCluster.Default.css' %}" />
<link rel="stylesheet" href="{% static 'css/map.css' %}">

<!-- Make sure you put this AFTER Leaflet's CSS -->
<script src="{% static 'js/leaflet-1.6.0/leaflet.js' %}" ></script>
<script src="{% static 'js/leaflet.markercluster-1.4.1/leaflet.markercluster.js' %}" ></script>
<script src="{% static 'js/Leaflet.FeatureGroup.SubGroup-1.0.2/leaflet.featuregroup.subgroup.js' %}" ></script>

{% load render_bundle from webpack_loader %}
{% render_bundle 'map' %}
<script type="text/javascript">

pageOptions = {
mapViewContainerId: 'mapContainer',
facilitiesURL : "{% url 'facilitiesJSON' %}",
supportersURL : "{% url 'supportersJSON' %}",
supporterListURL : "{% url 'list_by_plz' 'COUNTRYCODE' 'PLZ' 0 %}",
hospitalListURL : "{% url 'hospital_list' 'COUNTRYCODE' 'PLZ' %}",
mapboxToken : "{{ mapbox_token }}",
createPopupTextStudent : (countrycode,city, plz, count, url) => `{% blocktrans %}In ${city}, (PLZ ${plz}) gibt es ${count} Helfer*innen.\n<a href="${url}" target="_blank">Detailansicht für Kliniken</a>{% endblocktrans %}`,
createPopupTextHospital : (countrycode,city, plz, count, url) => `{% blocktrans %}In ${city}, (PLZ ${plz}) gibt es ${count} Orte an denen Hilfe gebraucht wird.\n<a href="${url}" target="_blank">Detailansicht</a>{% endblocktrans %}`,
createFacilitiesCountText: (count) => `<img src="{% static 'img/map/facility-marker.svg' %}"> ${count} {% trans "Einrichtungen" %}`,
createSupportersCountText: (count) => `<img src="{% static 'img/map/supporter-marker.svg' %}"> ${count} {% trans "Helfende" %}`,
facilityIcon: L.icon({
iconUrl: "{% static 'img/map/facility-marker.svg' %}",
iconSize: [40, 40],
}),
}
document.addEventListener("DOMContentLoaded", function domReady() {
let mapViewPage = new MapViewPage({
mapViewContainerId: 'mapContainer',
facilitiesURL : "{% url 'facilitiesJSON' %}",
supportersURL : "{% url 'supportersJSON' %}",
supporterListURL : "{% url 'list_by_plz' 'COUNTRYCODE' 'PLZ' 0 %}",
hospitalListURL : "{% url 'hospital_list' 'COUNTRYCODE' 'PLZ' %}",
mapboxToken : '{{ mapbox_token }}',
createPopupTextStudent : (countrycode,city, plz, count, url) => `{% blocktrans %}In ${city}, (PLZ ${plz}) gibt es ${count} Helfer*innen.\n<a href="${url}" target="_blank">Detailansicht für Kliniken</a>{% endblocktrans %}`,
createPopupTextHospital : (countrycode,city, plz, count, url) => `{% blocktrans %}In ${city}, (PLZ ${plz}) gibt es ${count} Orte an denen Hilfe gebraucht wird.\n<a href="${url}" target="_blank">Detailansicht</a>{% endblocktrans %}`,
createFacilitiesCountText: (count) => `<img src="{% static 'img/map/facility-marker.svg' %}"> ${count} {% trans "Einrichtungen" %}`,
createSupportersCountText: (count) => `<img src="{% static 'img/map/supporter-marker.svg' %}"> ${count} {% trans "Helfende" %}`,
facilityIcon: L.icon({
iconUrl: "{% static 'img/map/facility-marker.svg' %}",
iconSize: [40, 40],
}),
})

mapViewPage.initializeMap()
mapViewPage.loadMapMarkers()
mapViewPage.registerEventHandlers(window)

})
</script>
<script type="text/javascript" src="{% static 'js/mapview.js' %}"></script>


{% endblock %}

Expand Down
Loading