I am making an autocomplete drop-down list for my Pokemon website, and while the autocompleting drop-down bit works, it's not displaying the HTML entities properly. When I set the input's value to the entity, it simply prints out the text (e.g. ↑ and not a literal up arrow). I'm not sure what I am doing wrong, but here is a simplified version of it:
// There are usually a lot more, but just for simplification only one is shown
const natures = [
{name: "Lonely (Atk ↑ Def↓)"}
]
const natureInput = document.querySelector(".natureInput");
const suggestionsPanelNature = document.querySelector(".natureSuggestions");
// This is just used to see whether they have chosen one of the options
let set_nature = 0;
natureInput.addEventListener('keyup', function() {
set_nature = 0;
const input = natureInput.value;
suggestionsPanelNature.innerHTML = '';
// Find all of the natures that start with the input
const suggestions = natures.filter(function(nature) {
return nature.name.toLowerCase().startsWith(input.toLowerCase());
});
suggestions.forEach(function(suggested) {
// Display all matching natures
const div = document.createElement("div");
div.onclick = function() {
set_nature = 1;
natureInput.value = suggested.name; // This is the line that seems to be causing issues
suggestionsPanelNature.innerHTML = '';
};
div.classList.add("suggestion");
div.innerHTML = suggested.name; // This line, however, works fine
suggestionsPanelNature.appendChild(div);
});
if (input === '') {
suggestionsPanelNature.innerHTML = '';
}
})
So if someone clicked the Lonely (Atk↑ Def↓) option, it would come up in the input box as Lonely (Atk↑ Def↓), which is not what I want.
If you need anymore information please ask, but otherwise thanks in advance.
Im assuming you have an HTML similar to
<input type="text" class="natureInput">
<div class="natureSuggestions"></div>
If that's the case, you just need to replace ↑ and ↓ with ↑ and ↓. The input element is just normal text, so no need to escape it (Not when the user is typing, nor when you change it via js)
Fiddle: https://jsfiddle.net/ng6er7ov/2/
(Tip; is always nice to post a complete example with html and js somewhere like jsfiddle so people can just see what you have, instead of having to guess based on the code)
Currently you are just setting the innerHTML to exactly the string you have in natures.name. HTML only escapes certain characters like & and < so you can add the ↑ character directly into your string.
Related
I have a task to create API using ExpressJS that will manage highlights which will be made on the frontend. How can I keep track of my highlighted text if someone updates a part of the text?
I was keeping the three starting and ending characters of the highlighted text. But a problem is, how will I manage those characters if the text is edited.
const { textH, allText } = req.body;
let chars = { };
const enclosingChars = (hLighted, theString) => {
let startingChars = null, endingChars = null;
const index = theString.indexOf(hLighted);
const last3 = index + hLighted.length;
if ((index - 3) > -1) startingChars = theString.substring(index - 3, index);
if ((index + 3) <= theString.length) endingChars = theString.substring(last3, last3 + 3);
return { startingChars, endingChars };
};
if (allText.includes(textH)) {
chars = enclosingChars(textH, allText);
}
chars.hLighted = textH;
If a part of the highlighted text is edited, I will delete the highlighted in my storage. If not, I want to check if my starting and ending characters have changed, then I change them accordingly.
But I don't know how to get that highlighted text if its index changed
so it will be not as easy as you think if you consider keeping track of edits outside of the highlighted text.
the text might contain more than one similar phrase/word (to the highlighted)
the newly inserted phrase might be similar to the highlighted one (worse if before the main one in terms of indices)
so if any of the above scenarios happens the indices will be of no use because you can fall to the wrong text
Do the following
a. when highlighting keep the following
1. the content : to make sure if the edit happens in there, you know it and you can act accordingly
2. keep track of the index range of your text even in case the shift is required (when the text before it is edited)
3. take a screenshot of the entire article and store it so that when an edit to the article happens you know exactly which part is edited. this will require to check word by word and see if any word in the new text is different from the word of the same index in the old (screenshot). and you can shift the ranges of the highlighted text accordingly.
Remember any edit that happens after the highlighted text is innocuous.
Hope this helps.
I just started learning Javascript and I am trying to implement a project that came into my mind. The project is a simple text editor that takes a text as an input does some corrections and posts an output with the fixed text.
The input text is imported as an array. Each line of the text is an object property. The inputText is for displaying the default text in the browser inside a div, and the outputText is the one I use for the editing.
inputText = loadStrings("v.txt");
outputText = inputText;
Now the input text has some sentences. The problem is that there are a lot of empty lines in between.
firstLine
secondLine
thirdLine
What I want to achieve, is to remove all empty lines, but one, so the output text looks like:
firstLine
secondLine
thirdLine
I am searching for a solution for almost 3 days now. I have managed to remove ALL empty lines, but that's not what i want. I want to remove empty lines if they are more than one, but don't make any change if there is only one empty line.
This piece of code is one of many i have tried. This will remove ALL empty lines:
(source: Remove empty elements from an array in Javascript )
outputText = outputText.filter(function(e){
return e.replace(/[\r\n]+/g, '\n')});
Here is the codepen with all HTML, CSS and the JS code I am using.
https://codepen.io/theokondak/pen/KrNNVz
Try this regex:
e.replace(/([\r\n]){2,}/g, '\n\n')});
This will only match two or more consecutive empty lines replacing by an empty line.
My test code:
var lines = 'firstLine\n\n\n\nsecodLine\n\n\n\n\n\n\nthirdLine';
/*
firstLine
secondLine
thirdLine
*/
console.log(lines.replace(/([\r\n]){2,}/g, '\n\n'));
/*
firstLine
secodLine
thirdLine
*/
Try:
outputText = outputText.filter(function(e){
return e.replace(/[\r\n]+/g, '\n\n')});
I am not sure about the filter function above. but try below one must work.
outputText = outputText.replace(/[\r\n]+/g, '\n\n');
replacing with two new lines is the simplest way. you will get what you want.
I don't know if loadStrings leaves newlines at the end of the line or not. I'll assume it does (based on some code I see on this page). If it ends up mangled, please say so.
It is definitely easier to do this on a single string, like Hélio Márcio Filho says. So in your case, where you start with an array, you could just join the array together,replace three or more newlines with just two, then split it back up into lines:
let outputText = inputText.join('').replace(/(?:\r?\n){3,}/g, '\n\n').
split(/\n/).map(line => line + "\n");
But you can also do it just with filter - you just need to know how many empty lines you just saw, and suppress the extra ones:
let empties = 0;
let outputText = inputText.filter(line => {
if (line.replace(/[\r\n]+/, '')) empties = 0;
else empties++;
return empties <= 1;
});
The other answers work with a single string, but you're using the loadStrings() function from Processing.js, which gives you an array of strings.
You could convert the array into a single string, or load the file as a single string, but it seems simplest to me if you just process the array. Something like this:
function reduceNewlines(inputArray){
var outputNewArray = [];
var previousLineWasNewline = false;
for(var i = 0; i < myArray.length; i++){
if(myArray[i] == ''){
if(!previousLineWasNewline){
outputArray.push('');
}
previousLineWasNewline = true;
}
else{
outputArray.push(myArray[i]);
previousLineWasNewline = true;
}
}
return outputArray;
}
Please note that I haven't tested this code, and there is probably a ton of room for improvement. But the general idea is there: you could write a function that processed the array and returned a new array with the consecutive newlines removed.
You might also consider pre-processing your text file so you don't have to do this at all.
First of all, I would like to thank everyone for trying to help. I studied all your replies, I've tested each of them and they all work (some with needed tweaking) as stand-alone code, but when I inserted them into my code, some things went wrong. So I struggled and came out with my own solution, which is greatly inspired by your comments.
So the code that worked in my case is :
function reduceNewlines(outputTextEditNewLines) {
for (let key = 0; key < outputTextEditNewLines.length; key++) {
if (outputTextEditNewLines[key] == '') outputTextEditNewLines[key] = '\n';
else outputTextEditNewLines[key] = outputTextEditNewLines[key];
}
arrayToString = outputTextEditNewLines.join(""); // convert object myArray to string
console.log(arrayToString.replace(/([\r\n]){1,}/g, '\n\n')); // exports the text as it should
return arrayToString.replace(/([\r\n]){1,}/g, '\n\n');
}
The console.log exports the text as it should. Now the next step for my project is to make this string print to the DOM as it prints in the console.log.
I have a web page with a form on it. The "submit" button is supposed to remain deactivated until the user fills in all the necessary fields. When they fill in a field, a checkmark appears next to it. When all the checkmarks are there, we're good to go.
A checkmark might be set by code like this:
if (whatever) checkLocation.innerHTML = CHECKMARK;
Here's the code I'm using to do the final check. It just loops through all the locations where there may be checkmarks. If it finds a location without a mark, it disables the submit button and leaves. If it gets through them all, it activates the button and returns true.
function checkSubmitButton() {
var button = document.getElementById(SUBMIT_BUTTON);
for (var i=0; i<CHECK_LOCATIONS.length; i++) { // should be for-each, but JS support is wonky
var element = document.getElementById(CHECK_LOCATIONS[i]);
console.log(CHECK_LOCATIONS[i] +": " +element.innerHTML);
// if found unchecked box, deactivate & leave
if (element.innerHTML != CHECKMARK) {
button.disabled = true;
return false;
}
}
// all true--activate!
console.log("ACTIVATING BUTTON!");
button.disabled = false;
return true;
}
Here's the problem: this works so long as the const CHECKMARK contains something simple, like "X". But specs call for a special HTML character to be used: in this case ✓, or ✓. When I do the comparison (in the if line) it ends up comparing the string "✓" to the string "✓". Since these two are not equal, it doesn't recognize a valid checkmark and the button never activates. How can I compare the contents of the HTML element my constant? (And hopefully make the code work even if down the road somebody replaces the checkmark with something else.)
Thanks.
There is no problem with the check character and it behaves exactly like the X character. The problem is, that your html have the checkmark character stored as html entity in hex string. If you compare checkmark to checkmark it works just fine: https://jsfiddle.net/m7yoh026/
What you can do in your case is to make sure the CHECKMARK variable is the actuall checkmark character, not the html entity.
Other option is to decode the html entity: https://jsfiddle.net/m7yoh026/3/
var CHECKMARK = '✓'
var decoded_checkmark = $('<textarea />').html(CHECKMARK).text();
console.log($('div')[0].innerHTML)
if ($('div')[0].innerHTML == decoded_checkmark) {
$('body').append('checkmark recognized<br>')
}
You can convert a character to its HTML entity equivalent like so:
var encoded = raw.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
return '&#'+i.charCodeAt(0)+';';
});
Well, here's what I ended up doing: I made a function called encodeHtml() that takes a character or string, writes it to a brand new div, and then returns what's contained in that div:
function encodeHtml(character) {
var element = document.createElement("div");
element.innerHTML = character;
return element.innerHTML;
}
Then I can compare to what it returns, since it automatically changes "✓" to "✓", and will work with any unforeseen changes to that character. It's a bit of a kludge, but it works. (It's still not clear to me why JavaScript does this automatic conversion...but there are many design choices in which JavaScript mystifies me, so there you go.)
Thanks all for the help.
i'm trying to live edit a text box value so that the result will be split every two character,
adding a column and starting from some default character.
what i have till now is this code, that obviously doesn't work:
$('#textboxtext').keyup(function (){
var text = $("#textboxtext").val();
//$(text).attr('maxlength', '12');
var splitted = text.match(/.{2}|.{1,2}/g);
var result = ("B8:27:EB:" + splitted.join(':'));
});
i need the live split and the default character inside the textbox but i really don't know where to start...
From your code, it seems like you're trying to create a text box that has some very specific behavior. It looks like it needs to format its value in such a way that it always begins with certain 'prefix' of B8:27:EB:, and every subsequent pair of characters is is separated by a :. This is actually a very complex behavior and you have to consider a number of different interactions (e.g. what happens when the user attempts to delete or modify the prefix). I usually try to avoid such complex controls if possible, however here is a quick implementation:
$('#textboxtext').keyup(function (e){
var prefix = "B8:27:EB:",
text = $(this).val(),
splitted, result;
if (text.indexOf(prefix) == 0)
text = text.substr(9);
else if (prefix.indexOf(text) == 0)
text = "";
text = text.replace(/:/g, '');
splitted = text.match(/.{1,2}/g) || [];
result = prefix + splitted.join(':');
$(this).val(result);
});
Demonstration
Type inside the text box and see what happens. Also note, there are all kinds of interaction that this implementation doesn't account for (e.g. right-clicking and pasting into the text box), but it's a start.
Considering features like EditArea's and CodeMirror's autocomplete, I was wondering if, like Dreamweaver, there is a way to detect if the last word you entered is in a certain list then provide the same kind of suggestion box but with the function's arguments. I imagine you would use a regular expression on the entire field or possibly split() the whole thing (or the current line) then use the length attribute of the array to find the last bit of text, then do something involving an indexOf-like operation; however, this seems like it would get a bit resource-intensive. It almost looks like I've answered my own question, but it always helps to fully explain one's quandary, especially publicly. There's gotta be a better solution than mine. I appreciate any input. Thank you.
Put the list of words to match in an object, have the text or options to display as the value. Then on keyup or keypress you can get the last word of the text area using a function like:
function showLastWord(id){
var el = document.getElementById(id);
var lastWord = el.value.match(/\w+$/);
return lastWord? lastWord[0] : '';
}
Then check if the word is in the list and do stuff appropriately.
Edit
A small example is:
<textarea onkeyup="showHelp(this);"></textarea>
<script>
var getLastWord = (function() {
re = /\w+$/;
return function (s){
var lastWord = s.match(re);
return lastWord? lastWord[0] : '';
}
}());
var keyWords = {foo:'foo was typed',bar:'bar was typed'};
function showHelp(el) {
var lastWord = getLastWord(el.value);
// Check for matching own property of keyWords
if (keyWords.hasOwnProperty(lastWord)) {
// Do stuff
console.log(keyWords[lastWord]);
}
}