Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allow line break with javascript + LivePreview

I'm making a website in two column, on the left, you can write, and it display on the right with a special design.
The thing is, I'd like to allow line break on the right side, but it doesn't display. How could I do that ?
here is a preview of my design. To see the full picture, here is a > Fiddle HERE

function wordsinblocks(self) {
      var demo = document.getElementById("demo"),
        initialText = demo.textContent,
        wordTags = initialText.split(" ").map(function(word) {
          return '<span class="word">' + word + '</span>';
        });

      demo.innerHTML = wordTags.join('');
      self.disabled = true;
      fitWords();
      window.addEventListener('resize', fitWords);
    }



    $(function() {
      $('textarea.source').livePreview({
        previewElement: $('p#demo'),
        allowedTags: ['p', 'strong', 'br', 'em', 'strike'],
        interval: 20
      });
    });

    window.onload = wordsinblocks(self);

    function fitWords() {
      var demo = document.getElementById("demo"),
        width = demo.offsetWidth,
        sizes = [7.69230769230769, 23.07692307692307, 46.15384615384614, 100],
        calculated = sizes.map(function(size) {
          return width * size / 100
        }),
        node,
        i,
        nodeWidth,
        match,
        index;


      for (i = 0; i < demo.childNodes.length; i++) {
        node = demo.childNodes[i];
        node.classList.remove('size-1', 'size-2', 'size-3', 'size-4');

        nodeWidth = node.clientWidth;
        match = calculated.filter(function(grid) {
          return grid >= nodeWidth;
        })[0];
        index = calculated.indexOf(match);


        node.classList.add('size-' + (index + 1));
      }
    }
like image 309
Yagayente Avatar asked May 24 '16 15:05

Yagayente


4 Answers

You can do inserting linebreaks whenever the Enter key is pressed. One way is to use .which or .keyCode:

$(document).keydown(function(e){
     var event = e.which || e.keyCode;
     if (event == 13){
          //do something like this
          return '<span class="word"><br/>' + word + '</span>';
     }
});

"13" is the character code for Enter. I've tested it in your code and it works fine. You just need to place it (alter it too) where it doesn't affect any of your functioning codes.

Second way is to copy exactly what is in the "Write" panel before doing some actions like separating the words by encapsulating them in different highlights, etc.


[UPDATE #1]

Just a piece of your code for testing.

function wordsinblocks(self) {
      var demo = document.getElementById("demo"),
        initialText = demo.textContent,
        wordTags = initialText.split(" ").map(function(word) {
          return '<span class="word">' + word + '</span>';
        });

      $(document).keydown(function(e){
          var event = e.which || e.keyCode;
          if (event == 13){
              demo.innerHTML = wordTags.join(' <br/> ');
          } else{
              demo.innerHTML = wordTags.join('');
          }
      });

      self.disabled = true;
      fitWords();
      window.addEventListener('resize', fitWords);
}

[UPDATE #2]

function wordsinblocks(self) {
      var demo = document.getElementById("demo"),
        initialText = demo.innerText.replace(/\n\r?/g,"<br/>"),
        wordTags = initialText.split(" ").map(function(word) {
          return '<span class="word">' + word + '</span>';
        });

      demo.innerHTML = wordTags.join('');
      self.disabled = true;
      fitWords();
      window.addEventListener('resize', fitWords);
}
like image 117
rhavendc Avatar answered Oct 04 '22 21:10

rhavendc


You need to split the source (what you write) by new line and then split each line by space.

Update wordsinblocks as:

function wordsinblocks(self) {
  var demo = document.getElementById("demo"),
    initialText = demo.innerText,
    wordTags = initialText.split(/\n/g).map(function(line) {
      var spanWord = line.split(/\s/g).filter(Boolean).map(function(word){
          return '<span class="word">' + word + '</span>';
      });

      return "<span class='line-break'>" + spanWord.join("") + "</span>";
    });

    demo.innerHTML = wordTags.join('');

    self.disabled = true;
    fitWords();
    window.addEventListener('resize', fitWords);
}

Update fitWords as

function fitWords() {
  var demo = document.getElementById("demo"),
    width = demo.offsetWidth,
    sizes = [7.69230769230769, 23.07692307692307, 46.15384615384614, 100],
    calculated = sizes.map(function(size) {
      return width * size / 100
    }),
    lineNode,
    node,
    i, k,
    nodeWidth,
    match,
    index;

  for (k = 0; k < demo.childNodes.length; k++) {
    lineNode = demo.childNodes[k];
    for(i = 0; i < lineNode.childNodes.length; i++) {
       node = lineNode.childNodes[i];
       node.classList.remove('size-1', 'size-2', 'size-3', 'size-4');

       nodeWidth = node.clientWidth;
       match = calculated.filter(function(grid) {
          return grid >= nodeWidth;
       })[0];
       index = calculated.indexOf(match);

       node.classList.add('size-' + (index + 1));
    }
  }
}

Add following style in your css

#demo .line-break:after {
   clear: both;
   display: table;
   content: ""
}

FIDDLE DEMO HERE

Hope, It helps you & let me know if i miss anything.

UPDATE for Multiple Line-Break

Update textarea.reloadPreview as

textarea.reloadPreview = function() {
    var previewString = this.val().replace(/\n/g,"<br>");
    if (previewString.length > 0) {
       previewString = this.htmlUnencode(previewString);
       previewString = previewString.replace(opts.paraRegExp, "<p>$1</p><p>$2</p>");
       previewString = previewString.replace(opts.lineBreakRegExp, "$1<br />$2");
       previewString = previewString.replace(allowedTagsRegExp, "<$1>");

    }

    try {
       // Workaround for a bug in jquery 1.3.2 which is fixed in 1.4
       preview[0].innerHTML = previewString;
    }
    catch (e) {
      alert("Sorry, but inserting a block element within is not allowed here.");
    }

    preview.updatingPreview = false;
    this.bind('keyup', this.handleKeyUp);
    wordsinblocks(self);
}

Update worksinblocks as

function wordsinblocks(self) {
  var demo = document.getElementById("demo"),
    initialText = demo.innerText,
    wordTags = initialText.split(/\n/g).map(function(line) {
      var spanWord = line.split(/\s/g).filter(Boolean).map(function(word){
          return '<span class="word">' + word + '</span>';
      });

      var result = spanWord.join("");
      result = result == "" ? "<span class='empty'></span>" : result;

      return "<span class='line-break'>" + result + "</span>";
    });

    demo.innerHTML = wordTags.join('');

    self.disabled = true;
    fitWords();
    window.addEventListener('resize', fitWords);
}

Add following styles in your css

#demo .line-break .empty {
    height: 25px;
    display: block
}

#demo .word {
    float: left;
    box-sizing: border-box;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    padding: 5px;
    padding-left: 10px;
    padding-right: 10px;
    font-size: 2.9vw;
    height: 25px;
    font-family: "helvetica";
    border: 1px solid black;
}

UPDATED FIDDLE HERE

like image 31
Mahedi Sabuj Avatar answered Oct 04 '22 21:10

Mahedi Sabuj


The short, hacky solution

Change wordsinblocks to

function wordsinblocks(self) {
  var demo = document.getElementById("demo"),
    initialText = demo.textContent.replace(new RegExp("\n", "g"), '<br>'),
    wordTags = initialText.split(" ").map(function(wordWithLineBreaks) {
      return wordWithLineBreaks.split('<br>').map(function(word, index, arr)    {
          return (word === '' ? '' : '<span class="word">' + word + '</span>') + 
        (index < arr.length - 1 ? '<div class="lb">&nbsp;</div>' : '') ;
      }).join('');
    });

  demo.innerHTML = wordTags.join('');
  self.disabled = true;
  fitWords();
  window.addEventListener('resize', fitWords);
}

In the for loop inside the fitWords function, add, after the first line in the loop:

if (node.tagName.toLowerCase() === 'div') continue;

Change

$(function() {
  $('textarea.source').livePreview({
    previewElement: $('p#demo'),
    allowedTags: ['p', 'strong', 'br', 'em', 'strike'],
    interval: 20
  });
});

to

$(function() {
  $('textarea.source').livePreview({
    previewElement: $('p#demo'),
    allowedTags: [],
    paraRegExp: new RegExp('something nobody will ever enter'),
    lineBreakRegExp: new RegExp('something nobody will ever enter'),
    interval: 20
  });
});

Add to the end of your css:

.lb {
  display: block;
  clear: both;
}

See jsfiddle for complete solution.

Some thoughts about the solution

Although, this solution works, it is far from optimal.

For example, the usage of the livePreview jQuery plugin does not make much sense because it seems that you don't need HTML support as your code is using the textContent property after livePreview has done it's job which effectively removes all HTML.

This is also the reason why inserting the line breaks (added by hitting the enter key) did not work in your original code. What happened was the following:

  • User enters some text with line breaks
  • livePreview replaces these line breaks with <br> due to the usage of the lineBreakRegExp option.
  • the textContent property returns only the text, meaning the <br>'s are lost again.

So actually, @Shlomi Hassid has provided a better, alothough incomplete, approach. Incomplete because the sizing of the boxes is missing.

like image 29
Christian Avatar answered Oct 04 '22 20:10

Christian


you can do it with css instead white-space: pre;

p {
  white-space: pre;
 }
like image 33
Kimtho6 Avatar answered Oct 04 '22 21:10

Kimtho6