Verify if spacebar is pressed and then use jQuery to add a hashtag with multi-language support

I am attempting to use jQuery to add a hashtag (#) after the user types and presses space. I have created a demonstration on CodePen.

In this demo, when you type something like (how are you), the JavaScript code will change it to (#how #are #you).

To achieve this, I am checking the words for adding the #(hashtag) tag using the function addHashtags(text) { ... }.

1-) Everything works correctly for English characters. However, I want to extend this functionality to support multiple languages. The issue arises when typing Turkish characters like (üğşıöç). For example, when I type the word (üzüm) or (hüseyin), the JavaScript should convert them to (#üzüm #hüseyin) but instead, it adds extra symbols like this: (#ü#zü#m #hü#seyin). (Issue Resolved)

2-) Another challenge is with other languages such as Arabic, Azerbaijan, Japanese, and so on. The JavaScript does not add the #(hashtag) tag when typing in these languages. For instance, typing (

私は家族と一緒に行きます
) or (
ผมไปกับครอบครัวของฉัน
) does not trigger any changes. This is a significant problem that requires a solution. (Issue Resolved)

3-) In the demo, I have used textInput. It works on mobile devices but not on Firefox. If I switch to using keypress, the code functions on Firefox but not on mobile. I need the code to work seamlessly across all devices. (Issue Resolved)

// Your custom JS code goes here...

Answer №1

I have created a solution that is close to perfect for you. Feel free to check it out on Codepen!

Here is the complete code:

var input;

function diez(event){
   var s = event.target.selectionStart;
   var e = event.target.selectionEnd;
   var v = event.target.value;
   var c = v.length;
       v = v.replace(/[^a-z0-9\s]/ig, ""); // line 8
   var a = v.split(" ");
   var b = [];

   /* Remove this if-block if you want undeletable diez */
   if(v == ""){
      event.target.value = v;
      return;
   }
   /* --- */

   for(var i = 0; i < a.length; i++){
      var token = a[i];
      if(i == 0) b.push("#" + token);
      else if(i > 0){
         var previous = a[i-1];
         if(previous.toLowerCase() != token.toLowerCase() && token != "")
            b.push("#" + token);
         else if (token == "")
            b.push(token);
      }
   }

   b = b.join(" ");
   c = b.length - c;
   event.target.value = b;
   event.target.selectionStart = s + c;
   event.target.selectionEnd = e + c;
}

$(document).ready(function() {
   input = document.getElementById("text");
   input.addEventListener("keyup", diez, true);
});
  • Uses jQuery solely for document ready event.
  • Saves user selection and cursor position.
  • Pure Vanilla Javascript code.
  • Swapped content-editable div with a proper <input>.
  • Triggers on keypress rather than space press.

UPDATE

  • You are restricted from typing special characters: only letters a-z, 0-9, and whitespaces are allowed. You can customize permitted characters in line 8 (e.g., Russian, Turkish).

  • Tokens that resemble each other are discarded.

Answer №2

JavaScript Regular Expressions in ES5 do not support Unicode characters out of the box. In order to work with Unicode literals, you need to use \u (Unicode escape sequences) or utilize libraries like XRegExp that provide Unicode properties support.

When you incorporate XRegExp into your project, you can convert traditional Regular Expressions into Unicode-aware patterns. This allows you to utilize Unicode properties such as \p{L} or shorthand \pL.

I made some adjustments to your code to enable this functionality:

text = XRegExp.replaceEach(text, [
            [/#\s*/g, ""],
            [/\s{2,}/g, " "],
            [XRegExp(`(?:\\s|^)([\\p{L}\\p{N}]+)(?=\\s|$)(?=.*\\s\\1(?=\\s|$))`, "gi"), ""],
            [XRegExp(`([\\p{N}\\p{L}]+)`, "g"), "#$1"]
         ]);

The first two regexes are familiar, but the third one may seem complex. By breaking it down, you will see that (?:\\s|^) and (?=\\s|$) equate to \b. However, due to the ASCII-only interpretation of word boundary by \b, I had to structure it that way.

Try the live demo!

Breakdown:

  • \p{L} matches any letter from any language.
  • \p{N} matches any numeric character in any script.

Learn more about Unicode categories.

Answer №3

To improve the code that replaces spaces with dashes, try using the following:

   $("body").on("keyup", "#text", function() {
      $("#ad_text").html($(this).html().replace(/\s/g,"-"));
      go();
   });

This will automatically update your #ad_text by replacing all spaces with dashes. After this change, transitioning to "#" should be relatively simple.

The original code was incorrectly calling .replace on the jQuery return item rather than the .html.

Answer №4

If you want to display the text "#Hi #bro #how #are #you?", you can achieve it using the following code:

$(document).ready(function() {
   $("body").on("keyup", "#text", function(e) {
      // Add space after pressing return
      if(e.keyCode == 13) { 
         $(this).text($(this).text()+' ');
      }
      // Format div content after pressing space or return
      if(e.keyCode == 32 || e.keyCode == 13) {
          var content =  $(this).text();
          // Format content
          content = '#' + content.replace(/#+/g, '').replace(/\s+/g, ' #');
          // Set content
          $(this).html(content);
          // Put cursor at the end of div
          cursorManager.setEndOfContenteditable(this);
      }
   });
});

The solution to move the cursor can be found in cursorManager.setEndOfContenteditable()

1) To detect duplicates, convert the content variable into an array using split(), check for duplicates in this array and then use join() to transform the array back into a string.

2) To prevent entering _-?*/()=&%+^#'<|>.,;! characters, write a function to remove these characters and call it every time a key is pressed. Include your function at the beginning of the keyup event function.

Answer №5

This simple Javascript function efficiently adds a unique tag to each word in a given string:

function addDiszTag(str){
        //  var str = "Hello there how are you?"
        str = str.split(' ');

        //Output will be converted to ["Hello", "there", "how", "are", "you?"]
        var transformedArr = [];
        str.forEach(function(word){transformedArr.push("#"+word) })

        // Resulting array: ["#Hello", "#there", "#how", "#are", "#you?"]

        return transformedArr.join(' '); 

       //Returns "#Hello #there #how #are #you?"

    }

An additional validation could be added to prevent duplicate tags from being generated. I hope this explanation is helpful!

Answer №6

JS does not have a strong understanding of Unicode, so you can use equivalent UTF-16 ranges instead that correspond to the \p{alnum} property.

I suggest pre-compiling this to store it in a global variable.

This regex will match a leading whitespace (or beginning of string) when followed by an alnum character. You can then replace it with the whitespace + #.

The regular expression pattern is for a leading whitespace:

/(^|\s)(?=<see below>/g;

where Rx is used globally like this:

newSrc = strSrc.replace(Rx, "$1#");

The regular expression pattern expressed rawly:

(^|\s)(?=(?:[\u0030-\u0039\u0041-\u005A...]))/g

Answer №7

My belief is that this solution will suffice.

ATTENTION: I find it peculiar why you specifically required hitting the space or enter key. However, doing so can lead to some complications. For instance, if someone changes their mind and deletes input with the backspace key, the output hash tags will remain unchanged as the event does not get triggered without hitting the spacebar. That's why I utilized the keyup function.

    $("body").on("keypress", "#text", function(e) {
        if (e.which > 33 && e.which < 48 || e.which > 57 && e.which < 65 || e.which > 90 && e.which < 96 || e.keyCode === 13)
        {
            e.preventDefault();
        }
    });
    $("body").on("keyup", "#text", function(e) {
        var array = new Array();
        var diez = new Array();

        temparray = $('.addiez').html().split(" ");
        l = temparray.length;
        temparray[l-1] = temparray[l-1].replace(/&nbsp;/gi,'');

        $.each(temparray, function(i, el){
            el = el.replace(/&nbsp;/gi,'');
            el = el.toLowerCase();
            if($.inArray(el, array) === -1) array.push(el);
        });

        for (var i = 0; i < array.length; i++) {
            diez[i] = "#" + array[i] + " ";
        }
        $("#ad_text").html(diez);
    });
  .container {
   position:relative;
   width:100%;
   max-width:600px;
   overflow:hidden;
   padding:10px;
   margin:0px auto;
   margin-top:50px;
}
* {
   box-sizing:border-box;
   -webkit-box-sizing:border-box;
   -moz-box-sizing:border-box;
}
.addiez {
   position:relative;
   width:100%;
   padding:30px;
   border:1px solid #d8dbdf;
   outline:none;
   font-family: helvetica, arial, sans-serif;
   -moz-osx-font-smoothing: grayscale;
   -webkit-font-smoothing: antialiased;
}
.addiez::-webkit-input-placeholder {
   /* Chrome/Opera/Safari */
   color: rgb(0, 0, 1);
}
.addiez[contentEditable=true]:empty:not(:focus):before  {
      content:attr(placeholder);
      color: #444;
    }

.note {
   position:relative;
   width:100%;
   padding:30px;
   font-weight:300;
   font-family: helvetica, arial, sans-serif;
   -moz-osx-font-smoothing: grayscale;
   -webkit-font-smoothing: antialiased;
   line-height:1.8rem;
   font-size:13px;
}
.ad_text {
   position:relative;
   width:100%;
   padding:10px 30px;
   overflow:hidden;
   font-weight:300;
   font-family: helvetica, arial, sans-serif;
   -moz-osx-font-smoothing: grayscale;
   -webkit-font-smoothing: antialiased;
   line-height:1.8rem;
   font-size:13px;
   text-transform: capitalize;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
   <div class="addiez" contenteditable="true" id="text" placeholder="Write something with space"></div>
   <div class="ad_text" id="ad_text"></div>
   
   <div class="note">For example: When you write like: Hi bro how are you? Then jquery should change this text like this:
   #Hi #bro #how #are #you? I meant when user pressed space or pressed enter then add diez tag before the text like my exapmle.</div>
</div>

I included text-transform: capitalize; because I prefer it :) However, you have the option to disable it if desired.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Web Browser Fails to Set Cookie during an Ajax Request

I am facing a perplexing issue. I have an AJAX call that triggers the processing of a login form and generates a cookie upon successful login. However, the web browser is failing to recognize the cookie. Upon troubleshooting, I have narrowed it down to so ...

Exploring the benefits of integrating Apache Thrift with TypeScript

After running the apache thrift compiler, I now have generated .js and .d.ts files. How do I incorporate these files into my current Angular2/Typescript project? I attempted to do so with the following lines of code: ///<reference path="./thrift.d.ts"/ ...

Issues arise when attempting to delete messages that have already been retrieved

Having trouble removing messages from a specific user without any success: bot.js client.on("message", (message) => { if (message.content === '$deleteuser') { message.channel.fetchMessages({limit: 10}).then(collec ...

What steps are needed to create a hover box that appears on the right side of my div?

I am attempting to customize the code found at this link so that the box slides to the left side instead of the right. I thought changing right: 0; to right: 100%; in the .overlay class would achieve this, but it is not working as expected. I want it to l ...

Merge two arrays of the same size to create a single array of strings

Looking to merge the values of two equal-sized arrays and create a third array like the one shown below. I'm in need of guidance as I have not been able to locate a built-in JavaScript method for this specific task. The goal is to construct an array o ...

What is the best way to make the current year the default selection in my Select control within Reactive Forms?

Hey there! I managed to create a select element that displays the current year, 5 years from the past, and 3 years from the future. But now I need to figure out how to make the current year the default selection using Reactive Forms. Any ideas on how to ac ...

Position divs to align text beside icons

I am currently working on a Bootstrap popover to display various pieces of information, each containing an icon and some text. Additionally, I am incorporating twig into this project. Here is the HTML structure: <span class="fa fa-user instructor-con ...

Fetching server-side JavaScript source from a relative path within an ASP file

My setup involves a local IIS server pointing to a virtual workspace at c:\projects Within my c:\projects directory, I have the following folder structure: Game src asp test.asp jquery jquery.min.js The test ...

What is the best method for incorporating an Angular Component within a CSS grid layout?

I recently started learning Angular and am currently working on a project that requires the use of a CSS grid layout. However, I'm facing an issue with inserting a component inside a grid area specified by grid-area. My attempt to achieve this in app ...

Importing a .js file into HTML with AJAX

The following JavaScript code is located within index.html between "<script type="text/javascript">" function callanular() { peticion_http = new XMLHttpRequest(); peticion_http.onreadystatechange = showContent; peticion_ht ...

Several dropdown menus within the same container, working independently of each other

I recently encountered an issue with a drop-down navigation bar. When I have multiple drop-downs and click on one, it opens as expected. However, if I then proceed to click on another drop-down while the first one is already open, both of them remain open ...

Whenever I try to relocate my HTML file that references three.js, the three.js library seems to malfunction and stop

Something strange is happening... I recently downloaded three.js into a directory named 'brick': git clone https://github.com/mrdoob/three.js.git which created a subdirectory: brick/three.js/ After navigating to brick/three.js/examples ...

Exploring the data types of dictionary elements in TypeScript

I have a model structured like this: class Model { from: number; values: { [id: string]: number }; originalValues: { [id: string]: number }; } After that, I initialize an array of models: I am trying to compare the values with the o ...

Variety of color palettes within a single style sheet

My theme features various styles, including different color schemes. Currently, I load the default CSS first and then an additional stylesheet with specific colors based on the chosen color scheme. However, this process is causing a delay in my site' ...

The CSS-styled button I created is designed to display a list and has the functionality of submitting

Whenever I click on a button, it's supposed to show a list of choices. But instead, it tries to submit the values in the text input field. Css .dropbtn { background-color: #3498DB; color: white; padding: 16px; font-size: 16px; border: none; cursor ...

How can I effectively address issues with jqGrid's sorting and paging functionality?

After making changes to the server-side code, it now looks like this: int nm = objects.ToList().Count; if (objects.ToList().Count > 0) return new PagedList(objects, nm, 1, 25, null); else return null; The JSON data has been updated as follows ...

NodeJs simple mock: Capturing query string parameters with ease

I'm currently developing a basic mock server using only JavaScript and Yarn. Simply put, I have this functional code snippet: function server() { (...) return { users: generate(userGenerator, 150) } This piece of code successfully generates 15 ...

Tips for serving a JSON text file to a client-side AJAX request from a Node.js server

I have a node.js web app running on an AWS Ubuntu server. The json data from an API is stored locally on the server in a file named data.json. My goal is to load this data via AJAX and display it on the client-side HTML. Below is my project directory str ...

Encountering the error message "Uncaught Error: [vuex] Getters must be functions, but 'getters.getters' is {}. This occurred while splitting the Vuex store into modules in Vue.js."

As a beginner in VUEX, I am experimenting with building a test application to dive deeper into the world of VUEX. I have organized my VUEX store into modules, where each module has its own getter.js file. Getters, actions, and mutations are imported into i ...

React Native animation encountered a rendering issue: Invalid transform scaleDisliked value: { "scaleDisliked": 1 }

While working on my react native app, I encountered an issue when trying to apply a transform:scale effect to an Animated.View component. I am using interpolate for this purpose, but unfortunately, I keep receiving the following error message: Render error ...