HTML Documents Extension - #628
Conversation
✅ Preview readyYour changes are live at: https://lively-cedar-291d5d94.skr.mubilop.com/ Built from |
|
But you were right about the Python extension it didnt really add anything new. I think this does add more features that that does. I'm checking right now to see if something like this already exists but i'm pretty sure it isn't |
I see you had added a block that helps to scale appropriately (id |
|
Could you make it so that multiple pages can be displayed at once? |
Steve0Greatness
left a comment
There was a problem hiding this comment.
A bit more of a general concern, but you should put this through Prettier, because this is formatted, in my opinion, a bit badly.
| width: "470", | ||
| }, | ||
| "ids": [], | ||
| "code":"" |
There was a problem hiding this comment.
This would probably require a bit of a restructure, but there are far safer and more efficient ways to handle HTML code. Storing it as a DOM would actually be a good idea, here.
| class HTMLtoCanvas { | ||
| constructor(runtime) { | ||
| // Initialize an array holding your default dropdown menu options | ||
| this.pages = {} |
There was a problem hiding this comment.
You'll probably want to use a Map instead of just an object, since maps are more optimized to change frequently.
| if (Scratch.gui) { | ||
| Scratch.gui.getBlockly().then(ScratchBlocks => { | ||
| ScratchBlocks.BlockSvg.registerCustomNotch("htmldocuments-coolshape", | ||
| "c 2 0 3 1 4 2 l 4 4 c 1 1 4 -7 4 2 h 3 c 1 -1 2 -2 3 -3 c 1 1 2 2 3 3 l 3 0 c 0 -9 3 -1 4 -2 l 4 -4 c 1 -1 2 -2 4 -2" | ||
| ) | ||
| ScratchBlocks.BlockSvg.registerCustomNotch("htmldocuments-coolshape2", | ||
| "c 0 2 0 8 4 8 c 6 0 10 -7 14 -5 c 4 -2 8 5 14 5 c 4 0 4 -6 4 -8" | ||
| ) | ||
| }); | ||
| } |
There was a problem hiding this comment.
These currently go unused.
| const el = document.createElement("div"); | ||
| el.innerHTML = this.pages[args.PAGE].code; |
| ] | ||
| }, | ||
| attr: { | ||
| acceptReporters: false, |
There was a problem hiding this comment.
This should probably be set to true, instead of false. This would necessitate the use of a DOM, however, as the way you're currently setting attributes by their name is unsafe if you allow direct input.
| { | ||
| opcode: 'eve', | ||
| blockType: Scratch.BlockType.HAT, | ||
| text: 'When listener for [ID] activated in [PAGE]', |
There was a problem hiding this comment.
For consistency, this should start with a lowercase letter.
| this.pages[args.PAGE].code = `${this.pages[args.PAGE].code}<!--begin my style--><style>` | ||
| this.pages[page].code = `${this.pages[page].code}.htmldocumentelement${args.TYPE}element${page}${args.NAME}{${args.PROPERTY}:${value}};` | ||
| this.pages[args.PAGE].code = `${this.pages[args.PAGE].code}</style><!--end my style-->` |
There was a problem hiding this comment.
In cases like these, it's easier to read if you use += `...` instead of = `${...}...`
| this.pages[args.PAGE].data.x = 5 | ||
| this.pages[args.PAGE].data.y = 5 | ||
| console.log(this.viewing) | ||
| console.log(document.querySelector("#htmlpage")) |
There was a problem hiding this comment.
There are a few spare console logs here and there in this extension, I'd recommend removing them before this gets merged.
| vm.runtime.targets.forEach(target => { | ||
| const blocks = target.blocks; | ||
| const scripts = blocks.getScripts(); | ||
|
|
||
| scripts.forEach(rootBlockId => { | ||
| const block = blocks.getBlock(rootBlockId); | ||
|
|
||
| if (block && block.opcode === targetOpcode) { | ||
| let hatValue = ''; | ||
| let hatValuea = ''; | ||
|
|
||
| // 1. Check if it's a Field (dropdown/fixed text) | ||
| if (block.fields && block.fields.ID && block.fields.PAGE) { | ||
| console.log(block.fields.ID.value) | ||
| hatValue = block.fields.ID.value; | ||
| hatValuea = block.fields.PAGE.value; | ||
| } | ||
| // 2. Check if it's an Input (text bubble) | ||
| else if (block.inputs && block.inputs.ID) { | ||
| const input = block.inputs.ID; | ||
| const inputa = block.inputs.PAGE; | ||
| // Dig into the 'shadow' block which holds the text value | ||
| const shadowBlock = blocks.getBlock(input.shadow); | ||
| const shadowBlocka = blocks.getBlock(inputa.shadow); | ||
| if (shadowBlock && shadowBlock.fields && shadowBlock.fields.TEXT && shadowBlocka && shadowBlocka.fields && shadowBlocka.fields.TEXT) { | ||
| hatValue = shadowBlock.fields.TEXT.value; | ||
| hatValuea = shadowBlocka.fields.TEXT.value; | ||
| } | ||
| } | ||
|
|
||
| // Compare and trigger | ||
| if (hatValue === triggerText && hatValuea === triggerTexta) { | ||
| vm.runtime._pushThread(rootBlockId, target); | ||
| } | ||
| } | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
runtime.startHats has the functionality to start hat blocks dependent on their values, already.
|
thanks for the feedback! i'll get to it. |
Well, there's Project Interfaces, which is a similar idea, but it doesn't allow for the creation of documents made up of HTML. |
|
i was thinking about that exact thing while i was making this. I wanted to give users more control and the ability to display and build their own webpage documents. |
|
can i use 'https://unpkg.com/html-dom-parser@latest/dist/html-dom-parser.min.js' for prettier |
|
or i can use this function function prettierInText(html) {
// Clean up existing whitespace and collapse it
let clean = html.replace(/\s*([<>])\s*/g, '$1').replace(/\s+/g, ' ');
let reg = /(<[^>]+>)/g;
let matches = clean.split(reg).filter(Boolean);
let formatted = '';
let pad = 0;
matches.forEach((token) => {
// Check if the token is a closing tag
if (token.match( /<\/\w+/ )) {
pad--;
}
// Add current line indentation
formatted += ' '.repeat(Math.max(0, pad)) + token + '\n';
// Check if the token is an opening tag (and not self-closing)
if (token.match( /<[^\/][^>]*[^>\/]>/ ) && !token.match(/<(input|img|br|hr|meta|link)/)) {
pad++;
}
});
return formatted.trim();
}
// Example Usage
const raw = '<div><h1>Title</h1><p>Text</p><img src="img.jpg"/></div>';
console.log(prettierInText(raw)); |
This seems to be very clearly AI generated. I don't know if you vibecoded this extension but if you did that's a biiiig no-no |
|
I typed this myself. But the function i just pasted was AI generated because I wanted to see if you would or would not want me to import the prettier. |
|
I don't paln on using the script I sent you but I want to verify if i'm ok to import perttier from https://unpkg.com/html-dom-parser@latest/dist/html-dom-parser.min.js' |
I built this off of my previous html to canvas extension that I made last year. |
Uh, I don't think that's Prettier, that's a DOM parser. Prettier is a code formatter, I was requesting that you reformat your code. |
|
OH. ok. it does have a html parser. You wnated me to format my code |
Yes. The JavaScript of the extension, that's what I want you to format. |
|
I'll do that when i post my new revided version that replies to your suggestions (I'm a good coder but a horrible formatter. I'm downloading prettier on vscode right now) |
Alright, you actually don't need to open a new PR, just push to the same branch that this PR is pulling from (main). |
|
Additionally, you can just use the builtin |
|
I got you. |
|
should i use that to insert elements into my iframe or change the entire this.pages[page].codeto a HTML DOM |
|
Used a map for |
The Document Object Model (DOM) is the system used to represent the contents of a Document as an Object. In the web, a document is normally some flavor of Standard Generalized Markup Language (SGML). The current standard for representing such documents as Objects, is to make each "Element" into one object, that object would then house each property of that Element, such as attributes and child Elements. Normally, this structure is installed in languages so that the Document can be controlled by, and better understood by, the developers of a program, and the program itself. There have been, in the past, propositions to standardize syntax for interacting with SGML inside of languages that often need to, such as JavaScript. Though JavaScript did not end up accepting this proposed standard. |
I know this is unrelated to the issue and will most likely be marked as off topic but Why are you Like This |
Because a DOM is safer than your current method. |
|
I'll disallow using <script> in the add text block |
|
@jwklong do you have a resolution for the comment I sent before your find? |
|
I will make it do whatever you think it should do if someone does that. I dont know what a user would expect if they did that. |
Actually, I'd argue, in part related to Jwk's argument, that this is actually a place where a DOM is better. You can set values on the thread ( Speaking of which, there should actually be a way to edit the child elements and text of an element after its creation. |
|
so the there is a thread var (an array) that contains elements to be created. i'm changing it right now to a dom |
|
changed to a DOM |
Refactor HTMLDocuments class to remove unused 'ids' property and update related methods to use 'code' for element queries.
|
Added new blocks and got rid of unessecary tracking of ids |
|
Didn't mean to close :slappingmyheademoji: |
I just made a big change in how this works so there are a lot of things to fix
IM NOT LYING THERE WERE LITERALLY 67 CONSOLE LOG STATEMENTS IN MY CODE






Create HTML webpages and display them on the stage

I'll make a documentation when I know what you think of this