Page 1 of 5

Projects new and old

PostPosted: Thu Jun 13, 2024 9:34 am
by John Robin Dove
Hi Clifton,

I had a look at DuoLingo https://en.duolingo.com/the other day. It's supposed to be the most successful language teaching program in the world at the moment. I tried it and surprisingly the exercises are very much like those in 'Text Reader', a program I created with Toolbook more than 20 years ago!
I didn't try to convert that to an online version because, at the time, I wasn't convinced that the Toolbook Actions system was any good. It was only when I got your Powerpac that I changed my mind.
I think the best feature of 'Text Reader' was its reading system. You can see it in action in this video. https://youtu.be/cUOeXvVBOVA

It was not too difficult to achieve this because text fields in Toolbook could be subdivided into words. This is not the case in dhtml exports. However I am making good progress despite the complexities. https://youtu.be/XqtkpxEUQJ8

I don't intend to make hundreds of new recordings and exercises. Instead I want to make a tool that allows teachers to do this themselves, along the lines of Médiacours. I know this is probably the wrong approach. Teachers love programs where they just click a button, sit back and watch their students working. The don't seem to like programs that require them to prepare material themselves.

In the old Toolbook version, I used hotwords of various colors. By clicking on them the user could obtain translations and explanations and also access a recorder to record sentences and compare pronunciation with the original.

To reproduce the reading system using TB/Powerpac/html/javascript, I have used a TB modifiable field which I believe is exported as a textarea. I have to use this because I think it's the only type of object that supports the setSelectionRange method. Is that correct?

I have found a way to make it possible to position the caret and select words and sentences but prevent any alteration of the text. Making it readonly is no good because the caret disappears so I just use keydown + e.preventDefault.

My question is: can I make a system that would allow hotwords to be inserted into the text? I think the answer is no but can you confirm this, please? You definitely can't put a hypertext link into the text of a textarea. Could you put it into the text of a different element maybe? Could you make a system that allows the user create hyperlinks dynamically? I don't think anything like this is achievable. Would you agree?
Instead I could use the single select listbox object that you gave me. So students would click on a line in a list rather than a hotword. What do you think?
John

Re: Projects new and old

PostPosted: Thu Jun 13, 2024 11:11 am
by Clifton
For this I would suggest using a simple div element and set the contentEditable property to "true". Now you can format and insert text to your heart's delight.
Example:
<div style="width: 300px; height:500px;" contentEditable="true">
This content should be editable, NOT edible.
</div>

You can use the PowerPac to enable and disable the property dynamically depending on what action is allowed for the user (you can use this.contentEditable, or tbfunction_userProperty()).

Also, check out setCaretPosition() as it allows setting the cursor in several amazing ways, even using regular expressions to find the spot to put the insertion point. It can do some of the heavy lifting for you.

I use a mixture of these features in The Almena Method typing program and the LearnToType.Today program.

As far and using colors, etc., you should really consider using a stylesheet and classnames. Then you can search for certain words by classname inside the div element.

You can make your words that use classnames clickable if that is desired too. Just give the word an id and use XML to create a click event on the word. This is much more predictable than using hotwords, which I would not recommend.

Let's say you wanted to insert the phrase "hello world" in blue after the phrase "Good morning":
  1. Locate the position in the innerHTML property of the field.
  2. var htm = this.innerHTML;
    var newWord = '<span class="blueWords">hello world</span>';
    htm = htm.replace( /Good morning/, newWord);
These are a few things that may be useful to you. Of course, you may come up with lots of ideas based on this little bit of information.

The PowerPac also has a function which removes HTML tags from the innerHTML property of a field. This may be useful when attempting to retreive the raw text of the div element without all the tags.

Enjoy!

Re: Projects new and old

PostPosted: Fri Jun 14, 2024 6:23 am
by John Robin Dove
Thanks very much for your suggestions. I am actually using setCaretPosition() already. I'm probably trying to solve too many problems at once right now. I think I'll need to consult you again later, if that's OK. At the moment I'm struggling with another problem. The text, which is pasted in by the user, must be divided into 'pages' for want of a better word. I need to know how many 'pages' are required.

UPDATE You'll be pleased to know I have managed to solve my latest problems myself. One of my solutions seems a bit hacky though. The problem is setting the scrollTop to 0 as soon as a text has been pasted into a previously empty field. I can't detect the pasting so I start a timer that checks if the field has more than 0 characters. This works but I don't think it's the best way to do this.

Re: Projects new and old

PostPosted: Tue Jun 18, 2024 5:52 am
by John Robin Dove
Hi Clifton,
You wrote: For this I would suggest using a simple div element and set the contentEditable property to "true". and I've been trying to implement this. When a Toolbook field's behavior is set to Allow users to enter or modify text in this field if it is enabled I believe that when exported it becomes a textarea. This is what I am using for my 'animated reading script'. Does the field not become a div when exported if I set it to Lock the text and activate mouse events if the field is enabled? Maybe it doesn't. If so, I'm not sure how to create a simple div element. My script relies on the setSelectionRange(start, end) method and apparently this method is only available for the textarea and input elements. How do I create an input? If I export the field as non-modifiable, even if I then set its contentEditable property to "true", my system no longer functions and an error message tells me that the setSelectionRange(start, end) method does not exist.

I have a plan B which is to use 2 different fields to contain the text, one modifiable, one non-modifiable and hide and show them as and when necessary but this would be a bit nore complicated.

Re: Projects new and old

PostPosted: Tue Jun 18, 2024 8:40 am
by Clifton
Check this reference out for how to select text in a contentEditable <div>:
https://stackoverflow.com/questions/6139107/programmatically-select-text-in-a-contenteditable-html-element

Re: Projects new and old

PostPosted: Tue Jun 18, 2024 10:19 am
by Clifton
Also explore this code example for finding caret position in a div element that is contentEditable:
https://stackoverflow.com/questions/3972014/get-contenteditable-caret-position

Re: Projects new and old

PostPosted: Wed Jun 19, 2024 7:18 am
by John Robin Dove
Thanks Clifton but it seems that a div, even when contentEditable is true, does not support the setSelectionRange(start, end) method. Please see: https://www.mediacours.com/tb_examples/divTextSelection.html and https://www.mediacours.com/tb_examples/divTextSelection.zip

Re: Projects new and old

PostPosted: Wed Jun 19, 2024 8:18 am
by Clifton
I rewrote PowerPac's caretPosition() to support <span> and <div> with contentEditable set to true. It is possible to set a selection but the functions that are used are not the same at the ones for setSelectionRange(). If I get a moment, I will see if I can create an example. I know it works, because similar routines are required to set the caret position using caretPosition().

One caveat I encountered during the rewrite:
    If you use anything other than basic character-based HTML (like &lt; for < symbols, etc.), then setting the selection past HTML <span> tags will be anomalous. I am looking into this further, but I think the issue is a browser problem, because the functions all say that the caret locations are correct, but setting positions on those locations if they are past the HTML <span> tags just fail to work. You can click the positions and type content into the <span> tags, but once they are present, JavaScript manipulation begins to fail. Even <b></b> tags cause caret positioning problems. The getter works, but the setter does not if they location is within or past the tags.
Otherwise, using contentEditable <span> and <div> elements allows for formatting not previously allowed in a textarea element.

Re: Projects new and old

PostPosted: Wed Jun 19, 2024 9:09 am
by John Robin Dove
Thanks Clifton. I imagine you can't resist a new challenge :) but don't worry if you don't have time immediately because I'm pretty sure my plan B would work seamlessly. I'd use a textarea for the 'animated reading' and a div or whatever to add different color words etc. I could just hide one and show the other whenever necessary and I don't think the user would be aware of the change.

Re: Projects new and old

PostPosted: Wed Jun 19, 2024 3:43 pm
by Clifton
Here is an example of comparing a contentEditable <div> and a ToolBook <textarea> field.
These examples are using the rewritten caretPostion().