2

Been given a bit of a curve ball... I have a textarea in which people can type an essay of an undetermined length.

I need to present what they have typed within a set of divs (each div is of the same fixed width and height). The text should flow from div to div. I should be able to rotate the divs.

CSS columns are a no go, due to poor browser support and the inability to rotate each column (a css column being a single element that is displayed as many).

The text needs to flow between each div sensibly like pages in a word processor.

All my attempts have failed. I tried to detect when the string hit the divs overflow, and split the string, stick it in another div, detect overflow and so on. It sort of worked, but resulted in some odd line breaks.

I've tried sending the text to the server, where I turn it into a PDF which is sent back to the client - but this is very problematic and slow.

I've tried using canvas to flow the text between multiple canvas elements, but couldn't get this to work properly.

I've googled and googled - and nobody seems to have a satisfactory solution?

Is anyone able to give me some pointers?

Thanks, Rob

Rob
  • 1,576
  • 3
  • 22
  • 52
  • Are you using a standard text area or some kind of input library, something like WYSIHTML would split paragraphs into `

    ` elements, which would be easier to manipulate

    – Matt Jun 30 '17 at 13:57
  • Thanks for the speedy comment :) Just a plain old textarea. I did try it with a wysiwyg but found it made things harder - as it was splitting between paragraphs and littering the place with broken tags. Not to mention as the text is meant to flow like a wordprocessor. – Rob Jun 30 '17 at 14:00
  • Sounds to me as though you need CSS Regions...unfortunately the [support](http://caniuse.com/#feat=css-regions) is very limited. – Paulie_D Jun 30 '17 at 14:04
  • Yep... wondering if its possible to emulate with Canvas? – Rob Jun 30 '17 at 14:11
  • Would it be possible to make each "page" a fixed height text area, upon detecting reaching the end you could automatically inject and move focus into a new one. This is instead of having one input which you then need to manipulate the contents of. – Matt Jun 30 '17 at 14:11
  • I thought about that... but it was terrible to type in. eg: If a user went back to the first text area and deleted a load of text - it wouldn't automatically update the flow in all other textareas... So I wrote some code to capture the text and update the text boxes - but it was extremely messy, and really annoying as it would update as you typed – Rob Jun 30 '17 at 14:16
  • https://github.com/FremyCompany/css-regions-polyfill - just discovered this... – Rob Jun 30 '17 at 14:20
  • it doesn't work very well.. – Rob Jun 30 '17 at 14:25
  • Anyone know of any server side solution? eg - I post the data, its 'flowed' dtp style, server side - and send back as html? – Rob Jun 30 '17 at 14:26
  • I'm experimenting with creating a custom input type now which we could have simulate the appearance of pages. This is no simple problem though1 – Matt Jun 30 '17 at 14:30

2 Answers2

1

I've put in a draft for a possible solution which I need to finish but I don't have the time now. Have a look and continue if you want.

var essay = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur sollicitudin neque nec imperdiet condimentum. Quisque nec pretium magna. Praesent suscipit placerat nibh, quis elementum tortor interdum id. In in aliquet turpis. Donec in accumsan nisl. Vestibulum et metus placerat, congue sapien sed, volutpat justo. Phasellus sit amet turpis vel est laoreet bibendum sed eu mauris. Mauris nec lorem euismod, luctus urna vel, imperdiet ex. Nam ex quam, ullamcorper sit amet pretium vel, ornare et purus. Integer hendrerit ullamcorper tortor sed venenatis. Ut ornare fermentum eleifend. Proin non porttitor diam. Etiam laoreet tellus at sapien laoreet, nec lacinia neque scelerisque.";
var elm = document.getElementsByClassName("div")[0];

for (var i = 0; i < essay.length; i++) {
  var character = essay.charAt(0);
  essay = essay.substring(1);
  $("div").html($("div").html() + character);
  if (checkOverflow(elm)) { alert("overflow"); break; /* return the last word from div to essay and move to next div */ }
}

function checkOverflow(el) {
  var curOverflow = el.style.overflow;
  if (!curOverflow || curOverflow === "visible") el.style.overflow = "hidden";
  var isOverflowing = el.clientWidth < el.scrollWidth || el.clientHeight < el.scrollHeight;
  el.style.overflow = curOverflow;
  return isOverflowing;
}
.div {
  height: 4em;
  width: 10em;
  padding: 1em;
  border: thin solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="div"></div>
Gerard
  • 15,418
  • 5
  • 30
  • 52
0

Ok, so I came up with this:

https://codepen.io/anon/pen/BZxoZG

Using vue.js and lodash

Basically, looping through the essay, finding all the line breaks '\n' (paragraphs) and splitting on them to create an array of paragraphs.

I then split each paragraph on spaces, to create an array of individual words.

Then, looping through the words I build up an array of lines, each line is 50 chars long (the number needed to fill width of div).

I then flatten the array, and chunk it so I get an array where each item contains 14 lines (14 lines being the height of page).

It seems to be working... I pasted lots of stories in, and they all work...

Pasting code here should codepen go down.

var app = new Vue({
    el: '#foo',
    data: {
        essay: ''
    },
    computed: {

        pages: function() {

            // Chunkstring taken from 
            // https://stackoverflow.com/questions/6632530/chunk-split-a-string-in-javascript-without-breaking-words

            function chunkString(s, len) {
                var curr = len,
                    prev = 0;
                output = [];
                while (s[curr]) {
                    if (s[curr++] == ' ') {
                        output.push(s.substring(prev, curr));
                        prev = curr;
                        curr += len;
                    } else {
                        var currReverse = curr;
                        do {
                            if (s.substring(currReverse - 1, currReverse) == ' ') {
                                output.push(s.substring(prev, currReverse));
                                prev = currReverse;
                                curr = currReverse + len;
                                break;
                            }
                            currReverse--;
                        } while (currReverse > prev)
                    }
                }
                output.push(s.substr(prev));
                return output;
            }



            var lines = [];
            var message = this.essay; // grab our essay text
            var sp = message.split('\n'); // split on new lines

            for (var i = 0; i < sp.length; i++) {
                lines.push(chunkString(sp[i], 50)); // split each 'line' into 50 char strings
            }

            for (var y = 0; y < lines.length; y++) {
                if (lines[y].length == 0) {
                    lines[y].push('<br>'); // new line, add line break
                }
            }


            var pagesArr = _.flatten(lines);



            pagesArr = pagesArr.map(function(line) {
                if (line == '<br>') {
                    return line; // we already have a BR so don't add one
                }
                return line + '<br>'; // to preserve line breaks
            });
            // lean on lodash... our essay box accomodates 14 lines.
            pagesArr = _.chunk(pagesArr, 14);

            for (var a = 0, b = pagesArr.length; a < b; a++) {
                pagesArr[a] = pagesArr[a].join(' '); //join for display purposes
                pagesArr[a] = pagesArr[a].replace(/^<br>/, ''); // replace br if first char in page
            }


            return pagesArr;

        }
    }
});


app.essay = `Dear Merrys:--As a subject appropriate to the season, I want to tell you about a New Year's breakfast which I had when I was a little girl. What do you think it was? A slice of dry bread and an apple. This is how it happened, and it is a true story, every word.

As we came down to breakfast that morning, with very shiny faces and spandy clean aprons, we found father alone in the dining-room.

"Happy New Year, papa! Where is mother?" we cried.

"A little boy came begging and said they were starving at home, so your mother went to see and--ah, here she is."

As papa spoke, in came mamma, looking very cold, rather sad, and very much excited.

"Children, don't begin till you hear what I have to say," she cried; and we sat staring at her, with the breakfast untouched before us.

"Not far away from here, lies a poor woman with a little new-born baby. Six children are huddled into one bed to keep from freezing, for they have no fire. There is nothing to eat over there; and the oldest boy came here to tell me they were starving this bitter cold day. My little girls, will you give them your breakfast, as a New Year's gift?"

We sat silent a minute, and looked at the nice, hot porridge, creamy milk, and good bread and butter; for we were brought up like English children, and never drank tea or coffee, or ate anything but porridge for our breakfast.

"I wish we'd eaten it up," thought I, for I was rather a selfish child, and very hungry.

"I'm so glad you come before we began," said Nan, cheerfully.

"May I go and help carry it to the poor, little children?" asked Beth, who had the tenderest heart that ever beat under a pinafore.

"I can carry the lassy pot," said little May, proudly giving the thing she loved best.

"And I shall take all the porridge," I burst in, heartily ashamed of my first feeling.

"You shall put on your things and help me, and when we come back, we'll get something to eat," said mother, beginning to pile the bread and butter into a big basket.

We were soon ready, and the procession set out. First, papa, with a basket of wood on one arm and coal on the other; mamma next, with a bundle of warm things and the teapot; Nan and I carried a pail of hot porridge between us, and each a pitcher of milk; Beth brought some cold meat, May the "lassy pot," and her old hood and boots; and Betsey, the girl, brought up the rear with a bag of potatoes and some meal.

Fortunately it was early, and we went along back streets, so few people saw us, and no one laughed at the funny party.

What a poor, bare, miserable place it was, to be sure,--broken windows, no fire, ragged clothes, wailing baby, sick mother, and a pile of pale, hungry children cuddled under one quilt, trying to keep warm. How the big eyes stared and the blue lips smiled as we came in!

"Ah, mein Gott! it is the good angels that come to us!" cried the poor woman, with tears of joy.

"Funny angels, in woollen hoods and red mittens," said I; and they all laughed.

Then we fell to work, and in fifteen minutes, it really did seem as if fairies had been at work there. Papa made a splendid fire in the old fireplace and stopped up the broken window with his own hat and coat. Mamma set the shivering children round the fire, and wrapped the poor woman in warm things. Betsey and the rest of us spread the table, and fed the starving little ones.

"Das ist gute!" "Oh, nice!" "Der angel--Kinder!" cried the poor things as they ate and smiled and basked in the warm blaze. We had never been called "angel-children" before, and we thought it very charming, especially I who had often been told I was "a regular Sancho." What fun it was! Papa, with a towel for an apron, fed the smallest child; mamma dressed the poor little new-born baby as tenderly as if it had been her own. Betsey gave the mother gruel and tea, and comforted her with assurance of better days for all. Nan, Lu, Beth, and May flew about among the seven children, talking and laughing and trying to understand their funny, broken English. It was a very happy breakfast, though we didn't get any of it; and when we came away, leaving them all so comfortable, and promising to bring clothes and food by and by, I think there were not in all the hungry little girls who gave away their breakfast, and contented themselves with a bit of bread and an apple of New Year's day.

https://americanliterature.com/author/louisa-may-alcott/short-story/cousin-tribulations-story
`

CSS

textarea {
  width: 400px;
  height: 400px;
}

#pages {
  width: 400px;
}

.page {
      color: #000;
    background: #fff;
    border: 1px solid #000;
    margin: 10px 0;
    width: 565px;
    height: 400px;
    padding: 20px;
    font-size: 23px;
    font-family: 'Roboto', sans-serif;
  float: left;
}

Html

<div id="foo">
     <textarea v-model="essay" placeholder="Type in your message">
     </textarea>

  <hr style="clear: both">
      <div v-for="(page,i) in pages" >
            <div class="page" v-html="page">
            </div>
        </div>
</div>
Rob
  • 1,576
  • 3
  • 22
  • 52