Repository: pyscript/pyscript

Issue:
Do not recycle lastElementChild in display
### Checklist

- [X] I added a descriptive title
- [X] I searched for other issues and couldn't find a solution or duplication
- [X] I already searched in Google and didn't find any good information or help

### What happened?

Instead of cleaning up the target container when `append=False` is used, we use the `lastElementChild` assuming that's the `div` we eventually previously created on *empty* containers.

The issues I see with this approach (this is PyScript classic too IIRC):

  * when `<py-script>` is a target, it's already a visual container
  * any element as target, is already a visual container
  * because of previous 2 points, it's never been too clear to me why we even need to create a `div` to append anything, but then all integration tests expect that so there must be a reason - **amend** [probably not](https://github.com/pyscript/pyscript/issues/1780#issuecomment-1742988864)
  * when `<script type="py">` is used, its `target` is already a visual container ... so that previous questions apply
  * in no circumstance, when `append=False`, we should reuse any previous content, as the new content goal is to replace it, whatever it was
  * checking for `lastElementChild` to then branch out logic when append means `element.append(new_content)` is also not super clear or useful, neither with new empty nodes, nor with already populated ones
  * there are containers that don't accept `div` as content at all (`<picture>` and `<video>` IIRC and to name a few)

Accordingly, we should (imho) improve the `display` `append` attribute story, as right now it's rather causing issues instead and weird edge cases, failing expectations.

### What browsers are you seeing the problem on? (if applicable)

_No response_

### Console info

_No response_

### Additional Context

_No response_


Discussion:
I've removed the needs-triage label because we've been discussing this in Discord for a while so that @leriomaggio provided dozen variant of the issue and all of those variants were solved by cleaning up upfront when `append=False` was used.
If i had to guess... I would say that the fact that we're creating a `div` to append things probably *doesn't* have a good reason. The code for `_write` (which underlies `display`) goes back a loooong way. Actually, all the way back to PyScript Alpha! Here's that code from the very first release:

https://github.com/pyscript/pyscript/blob/5d49c20ade547e8a4e1b9fcc4a6a40eb3dc0effe/pyscriptjs/src/pyscript.py#L111-L129

As such, I think it would be fair to say that `_write` has some bad parts that we should feel free to correct.

Resolving patch:
diff --git a/pyscript.core/src/stdlib/pyscript/display.py b/pyscript.core/src/stdlib/pyscript/display.py
--- a/pyscript.core/src/stdlib/pyscript/display.py
+++ b/pyscript.core/src/stdlib/pyscript/display.py
@@ -3,7 +3,7 @@
 import io
 import re
 
-from pyscript.magic_js import document, window, current_target
+from pyscript.magic_js import current_target, document, window
 
 _MIME_METHODS = {
     "__repr__": "text/plain",
@@ -154,8 +154,10 @@ def display(*values, target=None, append=True):
     # if element is a <script type="py">, it has a 'target' attribute which
     # points to the visual element holding the displayed values. In that case,
     # use that.
-    if element.tagName == 'SCRIPT' and hasattr(element, 'target'):
+    if element.tagName == "SCRIPT" and hasattr(element, "target"):
         element = element.target
 
     for v in values:
+        if not append:
+            element.replaceChildren()
         _write(element, v, append=append)


Test patch: