简体   繁体   中英

Text pagination inside a DIV with image

I want to paginate a text in some div so it will fit the allowed area
Logic is pretty simple:
1. split text into words
2. add word by word into and calculate element height
3. if we exceed the height - create next page

It works quite good
在此处输入图片说明

here is JS function i've used:

function paginate() {
    var newPage = $('<pre class="text-page" />');
    contentBox.empty().append(newPage);
    var betterPageText='';
    var pageNum = 0;
    var isNewPage = false;

    var lineHeight = parseInt(contentBox.css('line-height'), 10);

    var wantedHeight = contentBox.height() - lineHeight;

    for (var i = 0; i < words.length; i++) {        
        if (isNewPage) {
            isNewPage = false;
        } else {            
            betterPageText = betterPageText + ' ' + words[i];
        }
        newPage.text(betterPageText + ' ...');
        if (newPage.height() >= wantedHeight) {
            pageNum++;
            if (pageNum > 0) {
                betterPageText = betterPageText + ' ...';
            }

            newPage.text(betterPageText);
            newPage.clone().insertBefore(newPage)            

            betterPageText = '...';
            isNewPage = true;
        } else {            
            newPage.text(betterPageText);
        }        
    }

    contentBox.craftyslide({ height: wantedHeight });
}

But when i add an image it break everything. In this case text overflows 'green' area.

在此处输入图片说明

Working fiddle: http://jsfiddle.net/74W4N/7/

Is there a better way to paginate the text and calculate element height?

Except the fact that there are many more variables to calculate,not just only the word width & height, but also new lines,margins paddings and how each browser outputs everything.

Then by adding an image (almost impossible if the image is higher or larger as the max width or height) if it's smaller it also has margins/paddings. and it could start at the end of a line and so break up everything again.basically only on the first page you could add an image simply by calculating it's width+margin and height+margin/lineheight. but that needs alot math to get the wanted result.

Said that i tried some time ago to write a similar script but stopped cause of to many problems and different browser results.

Now reading your question i came across something that i read some time ago:

-webkit-column-count 

so i made a different approach of your function that leaves out all this calculations.

don't judge the code as i wrote it just now.(i tested on chrome, other browsers need different prefixes.)

var div=document.getElementsByTagName('div')[0].firstChild,
maxWidth=300,
maxHeigth=200,
div.style.width=maxWidth+'px';
currentHeight=div.offsetHeight;
columns=Math.ceil(currentHeight/maxHeigth);
div.style['-webkit-column-count']=columns;
div.style.width=(maxWidth*columns)+'px';
div.style['-webkit-transition']='all 700ms ease';
div.style['-webkit-column-gap']='0px';
//if you change the column-gap you need to
//add padding before calculating the normal div.
//also the line height should be an integer that
// is divisible of the max height 

here is an Example

http://jsfiddle.net/HNF3d/10/

adding an image smaller than the max height & width in the first page would not mess up everything.

and it looks like it's supported by all modern browsers now.(with the correct prefixes)

In my experience, trying to calculate and reposition text in HTML is almost an exercise in futility. There are too many variations among browsers, operating systems, and font issues.

My suggestion would be to take advantage of the overflow CSS property. This, combined with using em sizing for heights, should allow you to define a div block that only shows a defined number of lines (regardless of the size and type of the font). Combine this with a bit of javascript to scroll the containing div element, and you have pagination.

I've hacked together a quick proof of concept in JSFiddle, which you can see here: http://jsfiddle.net/8CMzY/1/

It's missing a previous button and a way of showing the number of pages, but these should be very simple additions.

EDIT: I originally linked to the wrong version for the JSFiddle concept

Solved by using jQuery.clone() method and performing all calculations on hidden copy of original HTML element

function paginate() {

     var section = $('.section');

     var cloneSection = section.clone().insertAfter(section).css({ position: 'absolute', left: -9999, width: section.width(), zIndex: -999 });

     cloneSection.css({ width: section.width() });

     var descBox = cloneSection.find('.holder-description').css({ height: 'auto' });

     var newPage = $('<pre class="text-page" />');
     contentBox.empty();
     descBox.empty();
     var betterPageText = '';
     var pageNum = 0;
     var isNewPage = false;

     var lineHeight = parseInt(contentBox.css('line-height'), 10);

     var wantedHeight = contentBox.height() - lineHeight;
     var oldText = '';

     for (var i = 0; i < words.length; i++) {
        if (isNewPage) {
           isNewPage = false;
           descBox.empty();
        }
        betterPageText = betterPageText + ' ' + words[i];

        oldText = betterPageText;

        descBox.text(betterPageText + ' ...');
        if (descBox.height() >= wantedHeight) {

           if (i != words.length - 1) {
              pageNum++;

              if (pageNum > 0) {
                 betterPageText = betterPageText + ' ...';
              }

              oldText += ' ... ';
           }

           newPage.text(oldText);
           newPage.clone().appendTo(contentBox);

           betterPageText = '... ';
           isNewPage = true;
        } else {
           descBox.text(betterPageText);
           if (i == words.length - 1) {
              newPage.text(betterPageText).appendTo(contentBox);
           }
        }
     }

     if (pageNum > 0) {
        contentBox.craftyslide({ height: wantedHeight });
     }

     cloneSection.remove();
}

live demo: http://jsfiddle.net/74W4N/19/

I actually came to an easier solution based on what @cocco has done, which also works in IE9. For me it was important to keep the backward compatibility and the animation and so on was irrelevant so I stripped them down. You can see it here: http://jsfiddle.net/HNF3d/63/

heart of it is the fact that I dont limit height and present horizontal pagination as vertical.

var parentDiv = div = document.getElementsByTagName('div')[0];
var div = parentDiv.firstChild,
    maxWidth = 300,
    maxHeigth = 200,

    t = function (e) {
        div.style.webkitTransform = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
        div.style["-ms-transform"] = 'translate(0,-' + ((e.target.textContent * 1 - 1) * maxHeigth) + 'px)';
    };

div.style.width = maxWidth + 'px';
currentHeight = div.offsetHeight;
columns = Math.ceil(currentHeight / maxHeigth);

links = [];
while (columns--) {
    links[columns] = '<span>' + (columns + 1) + '</span>';
}
var l = document.createElement('div');
l.innerHTML = links.join('');
l.onclick = t;
document.body.appendChild(l)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM