javascriptdomtextgoogle-chrome-extensionpre

Resize text inside <pre> element like <textarea>


I want to resize my text inside pre element like textarea, for example if you set columns of textarea equal to 10 and your text exceeds that, then the text will go to next line.

How can I do that with pre element? What is the technical term?

Note that I need to use pre element because it reads \n and \r, and textarea does not allow to append a button under it (why?).

An example:

enter image description here

I present a dummy scenario below (working code) to illustrate my issue(s).

  <!DOCTYPE html>
    <html>
        <head>
            <button onclick="call()">Click</button>
        </body>
        <script>
     function call(){
    view = window.open("","Viewer", "width=400,height=600, resizable=no");
    view.document.write('<div id="id_1"</div>');
        t=["asdf", "sasdfasdfasdfasdfasd", "sasdfasdfasdfasdfasd"]
        id = view.document.getElementById("id_1");
        for (var i = 0; i < 3; i++){
    
            if (i % 2 == 0){
            
            ed_1 = document.createElement("pre");
            ed_1.id = "edt_"+i;
            ed_1.textContent = t[i];
            id.appendChild(ed_1);
            
            prnt = view.document.getElementById("edt_"+i);
            edb_1 = document.createElement("button");
            nextline_gap_1 = document.createElement("br");      
            edb_1.innerHTML = "Button no = "+i;
            edb_1.id = i;
            prnt.appendChild(nextline_gap_1);           
            prnt.appendChild(edb_1);    
                              }
                              else{
           text_a = document.createElement("textarea");     
            text_a.readOnly = "true";
            text_a.cols = "10"; 
            text_a.id = "edt_"+i;
            text_a.textContent = t[i];
            id.appendChild(text_a);
            
            
            prnt = view.document.getElementById("edt_"+i);
            edb_1 = document.createElement("button");
            nextline_gap_1 = document.createElement("br");      
            edb_1.innerHTML = "Button no = "+i;
            edb_1.id = i;
            prnt.appendChild(nextline_gap_1);           
            prnt.appendChild(edb_1);          
                             } } }
        </script>
    </html>

Solution

  • There are numerous problems with your code :

    1. You should avoid using the onevent attributes, like onclick="call()", use addEventListener instead.

    2. You should avoid using document.write, it's better to create a documentFragment and append it to the popup.

    3. You do not need to manually loop over your array, just use Array.forEach.

    4. You have not declared any of your variables.

    5. You code is not very DRY. You have repeated statements that could be written only once higher in the scope.

    6. You do not need to select elements that you have appended to the popup because you already have a reference to them.

    7. You cannot nest a button inside of a textarea.

    8. You should use CSS margins to add white-space, not <br> elements. These are meant to be used for linebreaks inside a paragraph only.

    9. <pre> elements have a specific white-space behavior that is different from other elements. You can override this with the white-space CSS property. You can also control wrapping of long unbroken strings of text with the overflow-wrap property.

    10. You can omit the cols attribute (which is based on average character width) and give your <pre> and <textarea> elements the same width using CSS rem or em units which are based on the width of a capital M at the current font size.

    Below you will find your code re-written in a way that accounts for all of the above points. Let me know if there is any aspect of it that you do not understand and I will explain further.

    <!DOCTYPE html>
    <title> Pre-Wrap Test </title>
    <button id="trigger">Click</button>
    <script>
      let trigger = document.getElementById('trigger');
      trigger.addEventListener('click', injectContent);
    
      let text = [
        'asdf',
        'sasdfasdfasdfasdfasd',
        'sasdfasdfsdfgh\nsdfasdfasddfghjk'
      ];
    
      function injectContent() {
        let view = window.open('', 'Viewer', 'width=400, height=600, resizable=no');
        let fragment = document.createDocumentFragment();
        let style = document.createElement('style');
        
        style.textContent = `
          pre {
            overflow-wrap: anywhere;
            white-space: normal;
          }
          
          textarea, pre {
            display: block;
            margin: 0;
            margin-bottom: 0.2rem;
            width: 8em;
            font-size: 0.8rem;
          }
    
          .wrapper {
            margin-bottom: 1rem;
          }
        `;
        
        fragment.append(style);
    
        text.forEach((t, i) => {
          let out = document.createElement('div');
          let btn = document.createElement('button');
          let box;
    
          out.className = 'wrapper';
    
          btn.textContent = `Button no = ${i}`;
          btn.id = `btn-${i}`;
          
          if (i % 2 == 0) {
            box = document.createElement('pre');
          } else {
            box = document.createElement('textarea');
            box.readOnly = "true";
          }
    
          box.id = `edt_${i}`;
          box.textContent = t;
          
          out.append(box);
          out.append(btn);
          
          fragment.append(out);
        });
        
        view.document.body.replaceChildren(fragment);
      }
    </script>