How to add a cursor/text position indicator to a <textarea> controlled by javascript? - html

I am making a typewriter like website (here) that uses a textarea and javascript (from button clicks) to add/remove from the textarea.
The next thing I want to add is an indicator to show where the next update (insert/remove) will be so I guess its always at the of the textarea value.
The key details that clash with other solutions are
The textarea is disabled (+ its a textarea and not a p tag)
Users add characters by using the buttons and not by typing with their keyboards
The user isn't selecting or has a selection while typing
Some solutions involve css that break the website
This is how I insert characters
function insert(char) {
document.getElementById("textarea").value += char
update()
}
to the textarea + a button
<textarea id="textarea" class="textarea" disabled>
</textarea>
<a onclick="insert('1')">
<div class="letterbox">
<p class="typewritter">1</p>
</div>
</a>
(btw I know I spelled typewriter wrong on the website and will fix that later)

If you want to make a custom insertion point (the blinking line) you can do that by adding and removing a chosen symbol ('|' for example) from the text with an interval. Perhaps something like this would do:
const insertionSymbol = '|';
const blinkInterval = 1000; // time in ms between insertion point updates
let blinking = true; // whether the insertion line is hidden
let textarea = document.getElementById('textarea');
setInterval(function() {
if(blinking) {
textarea.value += insertionSymbol;
} else {
textarea.value = textarea.value.slice(0,-1);
}
blinking = !blinking;
}, blinkInterval);
that would require you to change the insert and delete functions:
function insert(char) {
if(blinking) {
textarea.value += char;
} else {
// inserting the character before the insertion point by removing the insertion point temporarily
textarea.value = textarea.value.slice(0,-1) + char + insertionSymbol;
}
}
function delete() {
if(blinking) {
textarea.value = textarea.slice(0,-1);
} else {
// deleting the character before the insertion point by removing the insertion point temporarily
textarea.value = textarea.value.slice(0,-2) + insertionSymbol;
}
}
This idea can be expanded. for example, if you want to add a insertion point cool-down (i.e. change the insertion point to stay visible for some time after an update, like you see in most text editors), you can change the interval to run every millisecond, and add a timer for the next update. like this:
// ... all the variable definitions like before
let timer = blinkInterval;
setInterval(function() {
timer --;
if(timer == 0) {
if(blinking) {
textarea.value += insertionSymbol;
} else {
textarea.value = textarea.value.slice(0,-1);
}
blinking = !blinking;
timer = blinkInterval;
}
}, 1);
function insert(char) {
if(blinking) {
blinking = false;
textarea.value += char + insertionSymbol;
} else {
// inserting the character before the insertion point by removing the insertion point temporarily
textarea.value = textarea.value.slice(0,-1) + char + insertionSymbol;
}
timer = blinkInterval;
}
function delete() {
if(blinking) {
blinking = false;
textarea.value = textarea.slice(0,-1) + insertionSymbol;
} else {
// deleting the character before the insertion point by removing the insertion point temporarily
textarea.value = textarea.value.slice(0,-2) + insertionSymbol;
}
timer = blinkInterval;
}
Note: I'm writing the code blindly (I didn't run it to see if it works) so I'm sorry in advance for any mistakes.

I think overriding textarea attributes is meaningless. The indicator that you want is already in it's characteristic.
Remove the disabled tag from your textarea and just block the keyboard pressing with the below code snippet. [because not using keyboard typing is your feature]
document.onkeydown = function (e) {
return false;
}
If you want to you can bind the function to focus action of the textarea.

My suggestion on this would be to have the textarea active, NOT disabled and always on focus. This way you will have the blinking effect you want. Then have a pointer-events:none css on the textarea so no one can click on it and you have the blink you want. So my steps would be:
Remove disabled from textarea
Add pointer-events:none css rule to the textarea
On the update() function I observe add either a focus or a click event so the textarea gets focus on each insert()

One way to do it would be to have a loop running non stop (with a requestAnimationFrame maybe ?) to add and remove a | character every other second, which would simulate the usual text position indicator you have inside most text areas

Related

ActionScript 3 textfield disable default cursor

I'm looking for a way in ActionScript 3 to allow the user to scroll a TextField (left to right) if the amount of text is greater than the TextField's width without the cursor changing to the flashing I.
The textfield is inside a MovieClip. I cannot use MouseChildren = false and selectable = false as both stop the textfield being scrollable.
Any ideas?
Well, the simplest way is to set the myTextField.selectable = false. The cursor doesn't change and the text field's content remains scrollable. Maybe I missed something here, but it works on my simple test.
If you're still open to suggestions...
(This is roll-over scrolling instead of mouse-down to scroll by dragging)
var scrollSize : int = 5; //# scrolling speed
tf.selectable = false;
tf.height = 25; //# (set height only if [tf] is already on Stage with text)
tf.addEventListener(MouseEvent.MOUSE_OVER, scroll_start);
tf.addEventListener(MouseEvent.MOUSE_OUT, scroll_stop);
function scroll_start (evt:MouseEvent) : void
{ tf.addEventListener(Event.ENTER_FRAME, handler_enterFrame ); }
function scroll_stop (evt:MouseEvent) : void
{ tf.removeEventListener(Event.ENTER_FRAME, handler_enterFrame ); }
function handler_enterFrame (evt:Event) : void
{
//# touch right edge = scroll text towards left
if ( tf.mouseX >= (tf.width - 10) ) { tf.scrollH += scrollSize; }
//# touch left edge = scroll text towards right
if ( tf.mouseX <= (tf.x + 10) )
{
if ( tf.scrollH > 0 ){ tf.scrollH -= scrollSize; }
else { /* do else here = Hurray */ }
}
}
There is a weird effect that only happens if you scroll fully to the end of text/sentence and then immediately scroll backwards, when it reaches zero scroll there is a "bounce" effect. Likely caused by Enter Frame event. Will check that later tonight if possible but the general concept is there in code...
Gotta fly but hope it helps...
I'd suggest the following:
switch off mouse interactivity for the child TextField
mc.mouseChildren = false;
mc.addEventListener(MouseEvent.MOUSE_WHEEL, scroll);
and scroll it manually:
private function scroll(e:MouseEvent):void{
tf.scrollV += e.delta;
}
Working example here
update:
To scroll text horizontally you need to change the scrollH property of the TextField, for example you may handle MOUSE_WHEEL event like this:
private function scroll(e:MouseEvent):void{
tf.scrollH -= e.delta;
}

The best method to create typewriter effect?

Hey everyone so I am creating a game that focuses on character to character interactivity. So when you interact with a character a chat box opens and the characters start talking to one another. I have the text setup like an old school typewriter effect one letter at a time. As of now I create it by typing each letter on separate frames and have them play through. When it gets to then end of the sentence in order for the user to go on to the next sentence I have a button that they tap Here is the code:
private function nextConvo(e:MouseEvent):void
{
nNext += 1;
trace(nNext);
if (nNext == 1)
{
conversation.gotoAndPlay(1);
}else
if (nNext == 2)
{
conversation.gotoAndPlay(117);
}
}
As you can see i set it up to play the next frame with the new conversation so on and so on. I have a lot more text to do I realized it will be really time consuming and wonder if there is a easier way.
A method to where it types the string in the text box and I can still use my button so when the user wants to see the next conversation they can press the next button.
I saw a video here of someone showing the code way of doing it but Not sure how I would implement the button without having to add a lot of new mouse listeners and timers. Code Method
Please any help would be appreciated.
Omg, yes, you will go nuts if you show one character per frame :)
The idea is to have a function to handle this for you that you have ONCE somewhere (for example, on your main timeline). Then you can call it from everywhere and just pass the text, textfield to type into and a button.
private var _myText:String;
private var _myTextField:TextField;
private var _myButton:Button;
private var _currentCharacterPosition:int;
public function typeText(text:String, myTextField:TextField myButton:Button):void
{
_myText = text;
_myTextField = myTextField;
_myButton = myButton;
_myButton.visible = false;
_currentCharacterPosition = 1;
typeNextCharacter();
}
private function typeNextCharacter():void
{
_myTextField.text = _myText.substr(0, _currentCharacterPosition);
if (_currentCharacterPosition == _myText.length)
{
// all text is typed out, show your button
myButton.visible = true;
}
else
{
// type next character. 0.2 is the delay between letters (200 ms)
_currentCharacterPosition++;
setTimeout(typeNextCharacter, 0.2);
}
}
Assuming you have the textfield and button in the same place (same frame), you could then do this in that frame:
_root.typeText("This is my text to type out", myTextField, myButton);

How to wait a while before adding elements in css? javascript?

I have a problem that I will explain.
I'm doing an animation in HTML5 and CSS3. My idea is that a plane is flying around and it launches a missile after a while. What I want to do is to make the missile appear after that time. I thought about doing that changing the z-Index property of my div (because I have the missile image into a div container) using javascript after a while (any time I choose). For doing that I found the sleep function at the bottom. I created the "appear" function that I know it works because It changes my zIndex value but it doesn't wait the 2 seconds I want.
I also thought I had the solution by using the visibility property, but I have the same problem, sleep function doesn't wait at all.
Any suggestions? Thanks
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
function appear(object){
sleep(200000);
var objective = document.getElementById(object);
objective.style.zIndex=1;
You can pass a function to the setTimeout function which will call that function in x milliseconds.
function waitForMe() {
alert('triggered!');
}
// Call waitForMe in 200000ms
setTimeout(waitForMe, 200000);
So for your example, you would want to use 2000 (2 seconds), not 200000 (200 seconds):
function appear(object) {
setTimeout(function () {
var objective = document.getElementById(object);
objective.style.zIndex=1;
}, 2000);
}
Hiding and showing an element
You can hide and show a method in a few ways:
Use z-index as you suggest, probably not the best way as we can actually hide it instead of sending it to the back of the page.
objective.style.zIndex = 1;
Use display, this hide the object completely.
// hide
objective.style.display = 'none';
// show
objective.style.display = 'block';
Use visibility, this will hide the object but it will still take up space in the page. This wouldn't matter if you're using position:fixed or position:absolute.
// hide
objective.style.visibility = 'hidden';
// show
objective.style.visibility = 'visible';
You can either create a div around the objective, and add it in with javascript like this
document.getElementById('objectivespan').innerHTML=imagehere;
Other than that, you can use
objective.style.visibility='hidden';
and change it to
objective.style.visibility='visible';
for the delay, use
function sleep(){
alert('slept');
}
SetTimeout('sleep', 10000);

How can I detect StaticText in AS3?

I have StaticText fields in my flash project and I need to run some code when the mouse is hovering over them. So I tried this code
stage.addEventListener(MouseEvent.MOUSE_OVER, mouseRollOver);
function mouseRollOver(event:MouseEvent):void {
var tf:StaticText = event.target as StaticText;
if (tf){
//my code
}
}
but it doesn't work. When I use dynamic text fields and replace StaticText with TextField in the var tf, it works fine. I also thought that I could get this thing working with static text fields if I could make the mouse detect not StaticText as a target but some kind of object that has certain text properties (like "selectable" set to true), but I couldn't figure out how to do this. Anyway, I need to detect a static text field as a target somehow. Any help would be appreciated.
Thanks in advance
Your best option would be to put the static text box in a movieclip, and then assign your code based around that. Static text boxes don't have instance names, and can't be manipulated.
It is hard to do this. See this link enter link description here
As you can see you can check if the DisplayObject is StaticText and by checking the mousX and MouseY properties you can find if the rollover is related to this field. By if you use Dynamic text and uncheck selectable field you will get a textfield that acts as StaticField
EDIT
this is an explanation what I mean:
Let we have a StaticText field into stage in Black flash document.
var myFieldLabel:StaticText
var i:uint;
//This for check for all staticFields in state and trace its text. It is possible and it is working. I my case I have only one field and I get reference to it in myFieldLabel:StaticText var. Also I change it's alpha to 0.3.
for (i = 0; i < this.numChildren; i++)
{
var displayitem:DisplayObject = this.getChildAt(i);
if (displayitem instanceof StaticText) {
trace("a static text field is item " + i + " on the display list");
myFieldLabel = StaticText(displayitem);
trace("and contains the text: " + myFieldLabel.text);
trace( myFieldLabel.mouseX);
myFieldLabel.alpha = 0.3;
}
}
//Adds event listener to the stage for mouse move event
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseRollOver);
//This is an event handler. I check if the mouse position is within the static field
function mouseRollOver(evnt:MouseEvent):void
{
if ( 0 <= myFieldLabel.mouseX && myFieldLabel.mouseX <= myFieldLabel.width && 0 <= myFieldLabel.mouseY && myFieldLabel.mouseY <= myFieldLabel.height )
{
mouseOverStaticText( evnt)
}
else
{
mouseNotOverStaticText( evnt)
}
}
// this two methods change the static field alpha. Thay are only to show that is posible to detect and manipulate some properties of the StaticField.
function mouseOverStaticText( evnt)
{
myFieldLabel.alpha = 1;
}
function mouseNotOverStaticText( evnt)
{
myFieldLabel.alpha = 0.3;
}
I'm not sure what is the purpose of the managing of the StaticText field. StaticText is not design to be managed if you have to do something this is almost sure that the field must not be a static - they can be dynamic ( without selectible property ) or can be capsulated with MovieClip or there can be a different solution in your case.

How can I add an event listener to scrolling content?

I want to put some mouse event to scrolling text in dynamic text field.
For example: I type several sentences into one dynamic text field. For each sentence, I want to have a different mouse event. Like this:
sentenceA.addEventListener(MouseEvent.CLICK, functionA);
function functionA(evt:MouseEvent):void
{
trace("bla");
}
How can I add an eventlistener to each sentence in the scrolling text? Because the position of the mouse event should move when the relative text scrolling.
here you go...
_txt.htmlText = "<a href='event:sentence1'>This is one sentenc.</a> <a href='event:sentence2'>This is another sentence.</a>"
_txt.addEventListener(TextEvent.LINK, clickCopyHandler);
function clickCopyHandler(e:TextEvent):void {
trace(e.text);
}
var sentences:Array = [ sentenceA, sentenceB, ...... ];
function clickAllText(e:MouseEvent):void
{
var index:int;
for each(var s:String in sentences)
{
index = dynamicTextField.text.indexOf(s);
if(index >= 0 && index <= 3)
{
//if the sentence is in the front
this["sentence"+sentences.indexOf(s)]();
break;
}
}
}
function sentence0():void
{
}
function sentence1():void
{
}
If that is not the case, you would need to either use different text fields, or
get the proximity of the mouse point to the sentence x and y location on the
display.
Take a closer look at flash.event.TextEvent.LINK, it's thrown when you click on html text which has an attribute href='event:someText'. Consider the following example
var tf:TextField = new TextField();
tf.htmlText = "<a href='event:first'>sentence1.</a><a href='event:second'>sentence2.</a>";
tf.addEventListener("link", clickHandler); //link is value of flash.event.TextEvent.LINK
function clickHandler(e:TextEvent):void {
//here should be something like the following
if (e.text == "first") sentence1();
else if (e.text == "second") sentence2();
}
well, I guess you caught the idea! The problem is that sentences are to be put into tag, but you can make links look like ordinary text. If that variant does not fits your needs, you may try to compare selection boundaries(tf.selectionBeginIndex and tf.selectionEndIndex) with boundaries of sentences after click.