buttons for reordering problems in a set details page - #3090
Conversation
|
I'm happy to defer to your recommendations here. I could withdraw this, or feed what you have described here to Claude. I probably won't directly intervene with coding changes myself on this one though. Whatever things here (and with the other PRs I've made today) that we can complete, it will affect the Accessibility Guide I'm trying to complete before the release. It's getting down to a pretty short list of known issues (as far as webwork2 goes, that is). |
|
We can perhaps go with this for now, and then change to what I was thinking of later when I have time to work on that. |
|
OK. I'll see what Claude can do for the smaller tweaks you identified. |
8737b32 to
726f2d4
Compare
|
The issues you found are at least mostly addressed now. The method I directed for the first issue (about overcrowding) is maybe not the best though. |
|
I find the "indent"/"outdent" terminology a bit ugly. Also, in a JITAR set it isn't really indentation. It is nesting, and in fact the wording everywhere else calls it nesting. |
|
There is another problem with this. Say problem 1 and 2 use the same file. Problem 2 will have an alert "This problem uses the same source file as number 1.". Then if I use the buttons to swap #1 with #2, now the new #1 still says "This problem uses the same source file as number 1.". I'm working on that. |
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
726f2d4 to
933857d
Compare
|
OK, the language (both user-facing and internal) is now about nest/denest instead of indent/outdent. Also I moved the alerts for "This problem uses the same source file as number 1." from the template to the javascript, so it can be recalculated as things move. This is probably already an issue with the current mouse-driven rearrangement tool. |
drgrice1
left a comment
There was a problem hiding this comment.
This is going to take some time to review and test properly. But here are some things I see at this point.
| if (!repeatFileText) return; | ||
|
|
||
| const shownYet = {}; | ||
| container.querySelectorAll('.psd_list_item').forEach((item) => { |
There was a problem hiding this comment.
Please change this to
| container.querySelectorAll('.psd_list_item').forEach((item) => { | |
| for (const item of container.querySelectorAll('.psd_list_item')) { |
and remove the ); on line 76 below.
Make the same change for the forEach uses on line 89 and 117.
The similar forEach calls in this file that already existed should be updated at some point. The for (const ...) construct is generally clearer for multi-line for loops. The forEach method is largely a remnant of the old days when a var automatically hoisted. With let and const that is no longer an issue. The forEach usage is still nice for named functions such as on line 112 below, and brief one liners such as line 80 below (although that returns the result of num.textContent = '' which is really not correct, and eslint would complain about that).
| if (!container) return; | ||
| [container, ...container.querySelectorAll('.sortable-branch')].forEach((list) => { | ||
| const items = list.querySelectorAll(':scope > .psd_list_item'); | ||
| items.forEach((item, index) => { |
There was a problem hiding this comment.
Please change this to
| items.forEach((item, index) => { | |
| for (const [index, item] of items.entries()) { |
and delete the ); on line 103.
I originally included this line in the previous comment, but realized this one might need more explanation because it works differently to iterate over the index and element.
| if (Object.prototype.hasOwnProperty.call(shownYet, sourceFile)) { | ||
| const alert = document.createElement('div'); | ||
| alert.className = 'alert alert-danger p-1 mb-2 fw-bold'; | ||
| alert.textContent = repeatFileText.replace('[_1]', shownYet[sourceFile]); | ||
| alertContainer.append(alert); | ||
| } else { | ||
| shownYet[sourceFile] = row.querySelector('.pdr_problem_number')?.textContent ?? ''; | ||
| } |
There was a problem hiding this comment.
Anytime that prototype hacking is being done, generally, you should question the code. There are advanced techniques that require accessing the prototype, but hasOwnProperty usage by itself is not one of them. It is highly questionable if the hasOwnProperty check is needed for a basic object that has no other properties or methods than the ones set locally. There is always the possibility of a conflict with a builtin method or property, and so it is good to check. Although, why would you use Object.prototype.hasOwnProperty.call for a locally defined object that can have no overrides that required the safety of that method. Calling showYet.hasOwnProperty is perfectly safe in this instance.
Although, the real problem is that using a bare object is the wrong thing to do, and the reason for the need of such mysterious incantations as hasOwnProperty at all. showYet should be a Map. A Map was introduced into JavaScript for exactly this purpose and has been around in all browsers for more than 10 years. So instead change line 56 above to const shownYet = new Map();, and change this to
| if (Object.prototype.hasOwnProperty.call(shownYet, sourceFile)) { | |
| const alert = document.createElement('div'); | |
| alert.className = 'alert alert-danger p-1 mb-2 fw-bold'; | |
| alert.textContent = repeatFileText.replace('[_1]', shownYet[sourceFile]); | |
| alertContainer.append(alert); | |
| } else { | |
| shownYet[sourceFile] = row.querySelector('.pdr_problem_number')?.textContent ?? ''; | |
| } | |
| if (shownYet.has(sourceFile)) { | |
| const alert = document.createElement('div'); | |
| alert.className = 'alert alert-danger p-1 mb-2 fw-bold'; | |
| alert.textContent = container.dataset.repeatFileText.replace('[_1]', shownYet.get(sourceFile)); | |
| alertContainer.append(alert); | |
| } else { | |
| shownYet.set(sourceFile, row.querySelector('.pdr_problem_number')?.textContent ?? ''); | |
| } |


When in the Set Details page, there will now be buttons on each problem to move a problem up/down in sequence. The mouse click-and-drag tool is still there, but these buttons give a keyboard accessible way to rearrange the problems.
If the set is a JITAR set, there are also buttons for indenting/outdenting problems.
Buttons are disabled when appropriate (like you can't move problem #1 up in the list).