Skip to content

Commit

Permalink
🪲 attempt to fix the delay of filters in public adventure (#5229)
Browse files Browse the repository at this point in the history
Fixes #5221 

**How to test?**
- go to `/public-adventures` 
- test the filters,
- we must test this on alpha before deploying to beta.
  • Loading branch information
hasan-sh authored Mar 11, 2024
1 parent 428b9f2 commit 54b9d3b
Show file tree
Hide file tree
Showing 10 changed files with 403 additions and 315 deletions.
13 changes: 13 additions & 0 deletions data-for-testing.json
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,19 @@
"tags": [
"test"
]
},
{
"id": "c9ccb61ae9334416aba972f5d5089939",
"date": 1709899719928,
"creator": "teacher2",
"name": "adventure2",
"level": "1",
"content": "<p>This is the explanation of my adventure! This way I can show a command: <code>{print}</code> But sometimes I might want to show a piece of code, like this:</p><pre><code class=\"language-python\">{ask} What's your name?\n{echo} so your name is</code></pre><p>&nbsp;</p>",
"language": "nl",
"levels": [
"1"
],
"public": 1
}
],
"tags": [
Expand Down
82 changes: 22 additions & 60 deletions static/js/appbundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -118632,13 +118632,18 @@ pygame.quit()
ZC({ Validation: Ch, Select: _r });

// static/js/public-adventures.ts
var levelSelect = document.getElementById("level-select");
var languageSelect = document.getElementById("language-select");
var tagsSelect = document.getElementById("tag-select");
var searchInput = document.getElementById("search_adventure");
var searchTimeout;
searchInput == null ? void 0 : searchInput.addEventListener("input", handleSearchInput);
document.addEventListener("DOMContentLoaded", () => {
var levelSelect;
var languageSelect;
var tagsSelect;
var searchInput;
function initializeVariables() {
levelSelect = document.getElementById("level-select");
languageSelect = document.getElementById("language-select");
tagsSelect = document.getElementById("tag-select");
searchInput = document.getElementById("search_adventure");
}
document.addEventListener("DOMContentLoaded", prepareDropdowns);
function prepareDropdowns() {
const options = document.querySelectorAll(".option");
options.forEach(function(option2) {
option2.addEventListener("click", function() {
Expand Down Expand Up @@ -118668,18 +118673,9 @@ pygame.quit()
dropdown.setAttribute("data-value", nextValue);
option2.classList.toggle("selected");
updateLabelText(dropdown);
updateDOM();
});
});
updateDOM();
setTimeout(() => {
if (!levelSelect)
return;
const level3 = levelSelect.getAttribute("data-value") || "";
const cloneBtn = document.getElementById(`clone_adventure_btn_${level3}`);
cloneBtn == null ? void 0 : cloneBtn.addEventListener("click", handleCloning);
}, 500);
});
}
function getSelectedOptions(_options) {
return Array.from(_options).filter((option2) => option2.classList.contains("selected")).map((option2) => {
var _a4;
Expand All @@ -118693,21 +118689,6 @@ pygame.quit()
const selectedOptions = getSelectedOptions(relativeOptions);
label.textContent = selectedOptions.length === 0 ? label.getAttribute("data-value") : selectedOptions.join(", ");
}
async function handleCloning(e) {
const target = e.target;
const adventureId = target.getAttribute("data-id");
try {
const data = await postJson(`public-adventures/clone/${adventureId}`);
modal.notifySuccess(data.message);
await updateDOM();
} catch (error2) {
modal.notifyError(error2.responseText);
}
}
function handleSearchInput() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(updateDOM, 500);
}
function updateURL() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
Expand All @@ -118722,39 +118703,20 @@ pygame.quit()
}
window.history.pushState({}, "", `${window.location.pathname}?${urlParams.toString()}`);
}
async function updateDOM() {
if (!levelSelect || !languageSelect || !tagsSelect)
return;
const level3 = levelSelect.getAttribute("data-value") || "";
const lanugage = languageSelect.getAttribute("data-value") || "";
const tags2 = tagsSelect.getAttribute("data-value") || "";
const response = await fetch(`public-adventures/filter?tag=${tags2}&lang=${lanugage}&level=${level3}&search=${searchInput == null ? void 0 : searchInput.value}`, {
method: "GET",
keepalive: true,
headers: {
"Content-Type": "application/json; charset=utf-8",
"Accept": "application/json"
}
});
const { html, js } = await response.json();
updateURL();
const publicAdventuresBody = document.getElementById("public-adventures-body");
if (publicAdventuresBody) {
publicAdventuresBody.innerHTML = html;
document.addEventListener("updateTSCode", (e) => {
setTimeout(() => {
initializeVariables();
const js = e.detail;
updateURL();
prepareDropdowns();
initialize({
lang: js.lang,
level: js.level,
level: parseInt(js.level),
keyword_language: js.lang,
javascriptPageOptions: js
});
levelSelect.setAttribute("data-value", js.level);
languageSelect.setAttribute("data-value", js.lang);
tagsSelect.setAttribute("data-value", js.tags);
initializeHighlightedCodeBlocks(publicAdventuresBody);
const cloneBtn = document.getElementById(`clone_adventure_btn_${level3}`);
cloneBtn == null ? void 0 : cloneBtn.addEventListener("click", handleCloning);
}
}
}, 500);
});

// static/js/adventure.ts
var import_ckeditor = __toModule(require_ckeditor());
Expand Down
4 changes: 2 additions & 2 deletions static/js/appbundle.js.map

Large diffs are not rendered by default.

117 changes: 29 additions & 88 deletions static/js/public-adventures.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import { modal } from './modal';
import { initialize } from "./initialize";
import { initializeHighlightedCodeBlocks } from "./app";
import { postJson } from "./comm";

// Get and initialize needed variables
const levelSelect = document.getElementById("level-select") as Element;
const languageSelect = document.getElementById("language-select") as Element;
const tagsSelect = document.getElementById("tag-select") as Element;

const searchInput = document.getElementById('search_adventure') as HTMLInputElement | null;
let searchTimeout: NodeJS.Timeout;

searchInput?.addEventListener('input', handleSearchInput);
let levelSelect: HTMLElement;
let languageSelect: HTMLElement;
let tagsSelect: HTMLElement;
let searchInput: HTMLInputElement;

function initializeVariables() {
// Get and initialize needed variables
levelSelect = document.getElementById("level-select") as HTMLElement;
languageSelect = document.getElementById("language-select") as HTMLElement;
tagsSelect = document.getElementById("tag-select") as HTMLElement;
searchInput = document.getElementById('search_adventure') as HTMLInputElement;
}

document.addEventListener("DOMContentLoaded", () => {
document.addEventListener("DOMContentLoaded", prepareDropdowns);

function prepareDropdowns() {
const options = document.querySelectorAll('.option');

options.forEach(function (option) {
Expand Down Expand Up @@ -51,25 +52,10 @@ document.addEventListener("DOMContentLoaded", () => {
option.classList.toggle('selected');

updateLabelText(dropdown);
updateDOM()
});
});
}




updateDOM()
setTimeout(() => {
if (!levelSelect)
return
// Since we render html as a string, the js is lost and thus any js needed
// has to be applied again.
const level = levelSelect.getAttribute("data-value") || "";
const cloneBtn = document.getElementById(`clone_adventure_btn_${level}`);
cloneBtn?.addEventListener('click', handleCloning);
}, 500)
})


function getSelectedOptions(_options: NodeListOf<Element>) {
return Array.from(_options)
Expand All @@ -87,31 +73,13 @@ function updateLabelText(dropdown: Element) {
}



async function handleCloning(e: MouseEvent) {
const target = e.target as HTMLElement;
const adventureId = target.getAttribute("data-id");
try {
const data = await postJson(`public-adventures/clone/${adventureId}`);
modal.notifySuccess(data.message)
await updateDOM();
} catch (error: any) {
modal.notifyError(error.responseText)
}
}

function handleSearchInput() {
clearTimeout(searchTimeout);
searchTimeout = setTimeout(updateDOM, 500);
}


function updateURL() {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const level = levelSelect.getAttribute("data-value") || "";
const lanugage = languageSelect.getAttribute("data-value") || "";
const tags = tagsSelect.getAttribute("data-value") || "";

urlParams.set('level', level)
urlParams.set('lang', lanugage)
urlParams.set('tag', tags)
Expand All @@ -122,43 +90,16 @@ function updateURL() {

}

async function updateDOM() {
if (!levelSelect || !languageSelect || !tagsSelect)
return
// Since the select has no default values, we don't want to pass undefined to the backend.
const level = levelSelect.getAttribute("data-value") || "";
const lanugage = languageSelect.getAttribute("data-value") || "";
const tags = tagsSelect.getAttribute("data-value") || "";
const response = await fetch(`public-adventures/filter?tag=${tags}`
+ `&lang=${lanugage}&level=${level}`
+ `&search=${searchInput?.value}`, {
method: 'GET',
keepalive: true,
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json',
},
});
const { html, js } = await response.json()
updateURL()

const publicAdventuresBody = document.getElementById('public-adventures-body') ;
if (publicAdventuresBody) {
publicAdventuresBody.innerHTML = html

// Since we render html as a string, the js is lost and thus any js needed
// has to be applied again.
initialize({lang: js.lang, level: js.level, keyword_language: js.lang,
javascriptPageOptions: js})

// reset data values for each filter.
levelSelect.setAttribute("data-value", js.level);
languageSelect.setAttribute("data-value", js.lang);
tagsSelect.setAttribute("data-value", js.tags);

initializeHighlightedCodeBlocks(publicAdventuresBody)

const cloneBtn = document.getElementById(`clone_adventure_btn_${level}`);
cloneBtn?.addEventListener('click', handleCloning);
}
}

document.addEventListener("updateTSCode", (e: any) => {
setTimeout(() => {
initializeVariables();
const js = e.detail;

updateURL();
prepareDropdowns();
initialize({lang: js.lang, level: parseInt(js.level), keyword_language: js.lang,
javascriptPageOptions: js
});
}, 500);
})
12 changes: 11 additions & 1 deletion templates/htmx-adventure-card.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{% else %} outline-blue-600
{% endif %}
"
id="adventure_{{adventure.id}}"
data-cy="{{ adventure.id }}"
data-lang="{{adventure.language or current_language().lang}}"
_="on removeMe remove me">
Expand Down Expand Up @@ -69,10 +70,19 @@
{% endif %}
{% else %}
{% if user["username"] != adventure["creator"] %}
<button class="green-btn" id="clone_adventure_btn_{{level}}"
<button class="green-btn"
hx-post="/public-adventures/clone/{{adventure.id}}"
hx-target="#adventure_{{adventure.id}}"
hx-swap="outerHTML"
_="on htmx:afterRequest
if detail.xhr.status == 200 then
hedyApp.modal.notifySuccess('{{_('adventure_cloned')}}')
end"
data-cy="clone_{{adventure.name}}"
data-id="{{adventure.id}}">{{_('clone')}}</button>
{% else %}
<a href="/for-teachers/customize-adventure/{{adventure.id}}"
data-cy="edit_{{adventure.name}}"
class="green-btn" id="edit_adventure_button">
{{_('edit_adventure')}}</a>
{% endif %}
Expand Down
5 changes: 5 additions & 0 deletions templates/public-adventures.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

{% block regular_content %}

<div id="public-adventures">

<div id="filters"
class="flex flex-col sm:flex-row items-center gap-2
justify-around bg-blue-400 shadow-md rounded-lg p-4 mb-4"
Expand Down Expand Up @@ -37,6 +39,8 @@
end">
{% for level in customizations["available_levels"] %}
<div class="option {% if selectedLevel|string == level|string %}selected{% endif %}"
hx-post="/public-adventures/filter"
hx-target="#public-adventures"
data-value="{{level}}"
>{{ level }}</div>
{% endfor %}
Expand Down Expand Up @@ -104,6 +108,7 @@
<div id="public-adventures-body">
{% include "public-adventures-body.html" %}
</div>
</div>


{% endblock %}
Loading

0 comments on commit 54b9d3b

Please sign in to comment.