Giter VIP home page Giter VIP logo

balance-text's Introduction

BalanceText

A utility to provide an alternate text wrapping algorithm. I hope to get this into the CSS spec, so it's implemented as an optional "polyfill". It already appears in the CSS Text Module Level 4 Editor's Draft.

The default text rendering algorithm is:

  1. Add 1 word at a time to the current line until the next word won't fit.
  2. Break text so that the next word starts on a new line.
  3. Repeat until all text has been rendered.

That algorithm guarantees that the text is rendered using the least number of lines, but when text is centered and wraps to more than 1 line, it can produce visually undesirable results such as a long line of centered text followed by a short line of centered text. What I want is for the text to be balanced across lines. By "balanced across lines", I mean that the text is rendered so that the amount of text on each line is about the same. This plugin implements a line-breaking algorithm to do that automatically.

How it works

Here is a simple Balance Text setup:

  <style type="text/css">
  /* Plugin looks for elements with class named "balance-text" */
  .balance-text {
      text-wrap: balance;  /* Apply (proposed) CSS style */
  }
  </style>

  <script src="balancetext.min.js"></script>
  <script>
    balanceText();
  </script>

See the demo provided or this online version for a working sample.

If you call balanceText(), Balance Text will automatically run on any elements with balance-text class:

  • when the page loads (DOM Ready event)
  • when it is resized

You may also manually trigger it, e.g. if you're dynamically adding text to the DOM:

    balanceText(el);       // Balance a single element
    balanceText([el, el]); // Balance a list of elements
    balanceText('.el');    // Balance a list of elements based on query selector

This will apply the balance-text formatting once. If you'd like to re-apply automatically during window resize, you can use pass an options parameter instead:

    balanceText(el, {watch: true});

If you need to manually re-balance all triggered elements, use:

    balanceText.updateWatched();

How to use with jQuery

This library used to be implemented as a jQuery plugin (as of v2.0.0) but was re-written as a native utility (as of 3.0.0). If you'd like to continue using the jQuery interface, you can continue using 2.0.0 (link below).

You can also migrate to balanceText() from jQuery using this guide (shown compared to the 2.0.0 interface):

    // Put the balanceText utility into "polyfill" mode
    // This was the default mode of the 2.0.0 jQuery plugin when it loaded
    $.ready(function() {
        balanceText(); 
    });

    // manually trigger on a list of elements
    balanceText($('.my-class')); // equivalent to $('.my-class').balanceText();

    // manually trigger on a list of elements and update on browser resize
    balanceText($('.my-class'), {watch: true}); // equivalent to $.balanceText('.my-class');

    // manually re-balance all triggered elements
    balanceText.updateWatched(); // equivalent to $.fn.balanceTextUpdate();

Use from a CDN

//cdnjs.cloudflare.com/ajax/libs/balance-text/3.3.1/balancetext.min.js

//cdn.jsdelivr.net/npm/[email protected]/balancetext.min.js

Legacy (3.2.1)

Support for Internet Explorer was dropped in v3.3.0, so use v3.2.1 for IE support.

//cdnjs.cloudflare.com/ajax/libs/balance-text/3.2.1/balancetext.min.js

//cdn.jsdelivr.net/npm/[email protected]/balancetext.min.js

Legacy (2.0.0)

Has a hard requirement on jQuery.

//cdnjs.cloudflare.com/ajax/libs/balance-text/2.0.0/jquery.balancetext.min.js

//cdn.jsdelivr.net/jquery.balancetext/2.0.0/jquery.balancetext.min.js

Requirements

BalanceText does not have any dependencies. BalanceText is designed to run in most modern browsers.

Development

Linting

Make sure the code passes ESLint

npm run lint

Minification

We minify using Uglify-JS

npm run build

Creating a new Release

  1. Pull Request:

    • Add a test
    • Update version numbers: package.json, bower.json
    • Update minifed version, if necessary: balancetext.min.js
    • Update README.md, including links to new not-yet-created CDNs
  2. Create new github Release

    • cloudflare CDN is automatically created
  3. Update npm

    • npm publish (may need to npm adduser)
    • jsdeliver CDN is automatically created
  4. Update vanity page: gh-pages branch

Contributing

Contributions are welcomed! Read the Contributing Guide for more information.

Changelog

  • v 1.0.x - Initial Release, bug fix by chrisbank, better break point detection mmcgahan
  • v 1.1.0 - Fix bugs submitted by rodneyrehm, colmjude
  • v 1.2.x - text-align:justify (hunterjm) line-height (jonathanpatt), right aligned text fix
  • v 1.3.x - Debounce resizing events, more accurate space width estimate
  • v 1.4.0 - Add support for nested tags (rileyjshaw)
  • v 1.5.0 - Re-balance text on resize for manually triggered selectors (rileyjshaw)
  • v 1.6.x - Add balanceTextUpdate() method (rileyjshaw), bug fixes (bfred-it)
  • v 1.7.0 - Hack for partially working with jQuery 3, remove deprecation warning
  • v 2.0.0 - Fix automatic updating of custom selectors for jQuery 3 (bfred-it)
  • v 3.0.0 - Remove the jQuery dependency (BrianGenisio, bfred-it)
  • v 3.1.x - Support for hyphens, white-space:nowrap
  • v 3.2.x - Support for unwatch (weotch), non-breaking-space fix (bjnsn)
  • v 3.3.x - Support Server Side rendering (jakimarks), accessibility fix (jonjahr)

balance-text's People

Contributors

bfred-it avatar briangenisio avatar chrisbank avatar coliff avatar hunterjm avatar jakimarks avatar jimaek avatar jonathanpatt avatar jonjahr avatar mmcgahan avatar pjg avatar redmunds avatar rileyjshaw avatar sreyemnayr avatar stevengill avatar weotch avatar wturrell avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

balance-text's Issues

safari for io6 hangs

I'm currently designing a webpage with this plugin. The page hangs on io6 when the plugin is updating the balanced wrap. To see the behavior yourself simply load http://www.graphikschmiede.at/spanisch24 on an iPhone, scroll down to the section "Leistungen" an then change the language by pressing "ES" or "FR" in the upper right corner of the page. Usually the german text simply transitions out to the left and the other text moves in from the right. On the iPhone everything is stuck for seconds.

I could track down the problem to the use of the resize-Eventhandler. When I deactivated "applyBalanceText" for the resize-Event the hangs disappeared.

In the next step I added a throttled event Handler for resize (see http://www.paulirish.com/2009/throttled-smartresize-jquery-event-handler/ for more information)

At http://www.graphikschmiede.at/spanisch24/test2.html you can see the working result. The changed plugin is at http://www.graphikschmiede.at/spanisch24/jquery.balancetext.min.js

Thanks for the great plugin and I'm looking forward to seeing it as a future W3C Standard some day ;)

Seems to ignore floats in container

If text to be balanced is constrained to smaller width by floating elements, that smaller width appears to be ignored and the text is balanced assuming the full width of the container. So balancing does not work in the presence of floating elements constraining the text.
(FWIW, in my case, I'd be fine if the width available in the first line is used for all subsequent lines rather than adjusting width as floats are cleared and/or new ones are encountered, but that's just a special case.)

Contained anchor tags are removed.

Hi,

If the block of text contains links these are removed once balanceText() is executed. It is highly likely people will want to balance blocks of text that contain links so it would be good if they persisted.

Breaking non-serializable state of child nodes

Hey there,

$this.html(removeBR($this.html()));        // strip <br> tags

is (potentially) breaking a whole lot of things. For example any jQuery.data() stored on a descendant node, or registered any event handlers on a descendant node. That sort of data is not serialized.

If removing <br> is all you want to achieve, try:

$this.find('br').remove();

This wont mutate existing elements (such as links). It also is much faster, as the DOM SubTree doesn't have to be serialized to string and then parsed to DOM again.

Bad committer info

Looks like all of my commits had a bad email reference. It means the history of this repo aren't lining up with a real person (gmail.org instead of gmail.com... oops!). I don't know how it happened. If you don't mind, it is relatively easy to fix... you run the following script on the repo:

#!/bin/sh

git filter-branch --env-filter '

OLD_EMAIL="[email protected]"
CORRECT_NAME="BrianGenisio"
CORRECT_EMAIL="[email protected]"

if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$CORRECT_NAME"
    export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$CORRECT_NAME"
    export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

And then you push the changes.

git push --force --tags origin 'refs/heads/*'

I got the instructions on how to fix it from Github's help site and I ran it on my other repo to fix the problem there as well our fork of your repo. If you don't want to do this kind of surgery on your repo, I understand. Just figured I'd throw it out there.

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on Greenkeeper branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please click the 'fix repo' button on account.greenkeeper.io.

Don't define functions within looped functions

Considering the following example, MyFoo is created 10 times, causing the garbage collector 10 times more garbage to clean than necessary:

for (var i = 0; i < 10; i++) {
  (function() {
    var MyFoo = function() {};
    var instance = new MyFoo();
  })();
}

Do not declare functions within looped functions (unless you need the closure hierarchy).

You can safely move NextWS_params outside of $.fn.balanceText. same goes for all other functions that don't use a closure-context-variable.

forEach used on Nodelist breaks in older browsers

In 3.1 there is a function recursiveCalcNoWrapOffsetsForLine which tries to use el.childNodes.forEach

This throws an error in at the very least Internet Explorer 11 and Edge.

I have reverted to 3.0 for now to fix this issue.

Unbalanced text flashes to balanced text

I see the unbalanced text 'flash' to the balance text in a jarring way (takes like a split second). Would it be a good idea to modify the script, so that text is hidden first (or made transparent) and shows again after is has been balanced to avoid this jarring experience?

Miscalculation when using custom fonts

Thanks for developing this amazing script!

I just wanted to flag this issue in case anyone else has experienced it.

I only notice the issue when loading a custom font (from MyFonts) where the text is be balanced across too many lines, so text that could easily fit on 2 lines would render over 3 lines.

I think the issue can be traced back to the nowrapHeight calculation. I've fixed the issue for myself by changing line 313 from $this.css('line-height', 'normal'); to $this.css('line-height', '1');

Newly added elements aren't balanced

Hi @redmunds!

I came across this while working on a PR for #55 and thought it deserved its own discussion.

With the current API ( $('.selector').balanceText() ), we balance only the current matching elements on the page. Any elements matching this selector that are added afterward are not balanced (on resize, subsequent calls to balanceText, etc). This is not how CSS rules generally work.

This is also different from how elements with a .balance-text class are treated. Whether they were added before or after balanceText was instantiated, they are still included in balancing since a fresh search is made at runtime.

I think that we should employ the method used by .balance-text across the board by keeping a list of selectors that should be balanced. I'm happy to take a first pass at this in a PR, but wanted your thoughts first.

Before I fix #55, we should come to a decision on the expected behaviour here.

Availability on cdnjs

It could be useful for BalanceText to be available via cdnjs. Would you mind tagging versions in this repository so it can be added?

It breaks events and animations at every run

I found that BT uses .html() extensively and that causes the loss of all child nodes and their attached event listeners, and it causes any running animations to stop.

I looked into the issue and it doesn't seem to have an easy fix. The major hurdle to overcome is the switch from searching break opportunities in a flat string to searching it across multiple nodes, particularly in "substringing" the DOM ('hello <span>world</span>'.substr(0, 13) is relatively easy on a string but not on the DOM).

Alternatively, we could leave the break opportunity algorithm alone and instead keep a copy of the existing DOM that will just get the <br>s once we find their places. The problem then would only be matching the found char index in the DOM. But that is difficult too.

What do you suggest?

$.balanceTextUpdate() should be $.fn.balanceTextUpdate()?

The README says to call $.balanceTextUpdate() to manually re-balance all triggered elements, but that causes Uncaught TypeError: $.balanceTextUpdate is not a function(…). Changing this to $.fn.balanceTextUpdate() seems to do the trick.

Escaped HTML is converted to unescaped HTML

For example, the following:

<p>&lt;u&gt; Escaped HTML Test Here! &lt;/u&gt;</p>

Will be converted to the following after applying balance-text, if it breaks any lines:

<p><u> Escaped HTML<br data-owner="balance-text">Test Here! </u></p>

Mixed font sizes don't work

The FONT SIZE TEST seems to be broken in test1.htm. It looks like the largest font size is being applied to all of the text.

Demo page is outdated

The demo page seems to still be using jquery.balancetext-1.2.0.js, but the project is now on 1.6.0. We should probably replace the lib with //cdnjs.cloudflare.com/ajax/libs/balance-text/1.6.0/jquery.balancetext.min.js.

In IE (9-10 tested), getting an unsupported object or method error

I'm receiving an "Object doesn't support property or method 'trimRight' in versions of IE 9-10 (only ones I tested) when using balance-text.js. It kills all subsequent js actions on the page. This error's only happening in IE. Works fine in Firefox and Chrome. See attached image.

image

Right aligned balanced text leaves space after last word on non-last lines

When balancing right-aligned text, the plugin accounts for the space after the last word on a line that is not the last line by leaving that space on the line, leaving text to not truly be flush right, but having a space in all lines that are not the last line of the balanced text.
screen shot 2013-12-24 at 1 33 43 pm

Unfortunately the above example is not live yet, but the same problem persists in the right-aligned text in the form element on the demo page linked from the balance-text github page. http://adobe-webplatform.github.io/balance-text/demo/index.html

Plugin needs to be rewritten for perf and silent usage

There have already been several issues posted about perf problems, but while this is an extremely good idea, it's implementation is fundamentally flawed. You should not need to individually specify which elements you are going to apply the break on. You should be able to specify HTML like this:

<p class="balancedText">Some long text here...</p>

and then you should be able to use $(".balancedText") to get all of the elements implementing the class. This would also integrate well with other UI libraries like Bootstrap, where you can compound classes for multiple effects. This article talks about the consequences of doing unnecessary .each() loops.

Speaking of Bootstrap, you should heavily consider structuring this code the way Bootstrap.js structures its plugins. You need to create a BalancedText code function, assign all of the internal functions to BalancedText.prototype (as specified in this issue), and optimize how you are applying the CSS classes (as specified in this issue. Both of these issues are causing the script to consume orders of magnitude more memory and compute cycles than it needs to.

Finally, instead of forcing the user to call window.on("resize", function() {reflow();}); themselves, your code should automatically handle it.

The end result would be a process that is completely transparent, just like Bootstrap. The end user should be able to reference the script, add the class to the elements they want to balance, and then view it in the browser. Because that is exactly how it will work when this standard is implemented. All they would have to do at that point is take out the script.

This is a great and well-needed concept. Once you refine the implementation to not be looping inside loops and make it so it runs silently, it will be as ubiquitous as the html5shiv.

Line break issue

Hi,

I've just found this awesome plugin and i was testing but i'm not sure why it's not working as expected.

screenshot 2013-10-12 11 11 45

I have a pretty wide div and i'd want the text to be in 2 lines not 3 :|

Any hints?

JQuery dependency

I there any particular reason why there is a JQuery dependency? Could this be done without it? My main reason is that I just want to save some KB an improve performance.

Maybe we could start Vanilla JS fork?

Syntax error in Internet Explorer: arrow function

Thanks for balance-text. It makes a real difference, and I hope I can continue to use it in projects, even those that require IE support. :)

Expected Behaviour

Works in IE, as per the comment in the source ('IE 9') and the guidance in the readme.

Actual Behaviour

SCRIPT1002: Syntax error
balancetext.js (71,12)

Steps to Reproduce

Include the script in the HTML document and load in any version of Internet Explorer.

<script src="https://cdnjs.cloudflare.com/ajax/libs/balance-text/3.3.0/balancetext.js"></script>

More information

Browser compatability information

Offending line

update jquery dependency

npm WARN deprecated [email protected]: Versions of the jquery npm package older than 1.9.0 are patched versions that don't work in web browsers. Please upgrade to >=1.11.0.

Consider using a range like "jquery": "1.9.1 - 3"

angularjs version of balance-text?

I'd like to make a non-jquery AngularJS version of this, based on your code.

Any objections? I've just read through the Apache licence and I think it says I can do that.

P.S. Thanks for sharing this plugin, I really love it.

Tag New Versions

Hey, Looks like the latest version wasn't tagged, would you mind doing so, similar to the discussion in #30.

Provide configuration options via the interface

One limitation I've hit a couple of times has been the 5000 character limit which is somewhat arbitrary. I changed some copy from 4990 to 5010 characters the other day and it all-of-a-sudden stopped working.

Is there a philosophical reason for a limit that large? Is it based on empirical evidence? Or is it mostly just arbitrary?

Was thinking we could have a way of changing that default? Perhaps globally, as well as per-call.

balanceText.config({maxTextWidth: 12345}); // global setting
balanceText(el, {maxTextWidth: 12345}); // per-call
balanceText(el, {anyTextWidth: true}); // perhaps just disable the check?

I'm happy to do the work if we decide this is the way to go... just thought I'd put it out there as a discussion point. Will there be other config settings we care about such that we setup a good pattern for it?

Disable stripping of tags

I have text with words highlighted using em tags. Is there any way to stop balance-text stripping the tags?

Server side rendering is broken

Seems like SSR is not supported in the current state.
This code is not SSR safe. It should probably look like this:

function hasTextWrap() {
       if (typeof window === 'undefined') {
            return false;
        }
        var style = document.documentElement.style;
        return style.textWrap || style.WebkitTextWrap || style.MozTextWrap || style.MsTextWrap;
    }

I would have opened a PR but this project is using jslint and it complains about it:

#1 Unexpected 'typeof'. Use '===' to compare directly with undefined.

But in this case it has to be checked like this because the window variable will not be declared at all for SSR. And I couldn't make the linter ignoring this line.
Would be good to make this work again for SSR as soon as possible.

Text should break on hyphens and dashes

I've noticed that the polyfill seems to avoid breaking hyphenated words, i.e. it treats each hyphenated word-pair as one word. I suspect this is because isBreakOpportunity (L258) relies solely on spaces. Appending || txt[index-1] == '-' solves the problem partially, but it doesn't account for n-dashes and m-dashes, and it causes persistent whitespace rifts to appear inside hyphenated words on repeated resize. I admit I haven't looked too deep into this issue.

In terms of use-case, I'm currently trying to make some centered blockquotes prettier automagically, and I'm running into issues with words like "nineteeth-century".

white-space: nowrap

Run into this a couple of times now where i have a two-part word that shouldn't be split.
Anyway we could have it respect white-space:nowrap spans?

Improve your use of jQuery.css()

Bad:

$this.css('position', oldPosition);
$this.css('display', oldDisplay);
$this.css('float', oldFloat);
$this.css('white-space', oldWS);

Good:

$this.css({
  'position': oldPosition,
  'display', oldDisplay,
  'float', oldFloat,
  'white-space', oldWS
});

Sadly the docs don't really explain why… For one it's less to type. Then the internal looping of $this's nodes is done only once. Then it allows an optimization (to write even less code) such as:

var oldStyle = {
    'white-space': $this.css('white-space'),
    'float': $this.css('float'),
    'display': $this.css('display'),
    'position': $this.css('position')
};
// ...
$this.css(oldStyle);

If you were targeting jQuery 1.9, you could also use the new "array argument":

var oldStyle = $this.css([
    'white-space',
    'float',
    'display',
    'position'
]);
// ...
$this.css(oldStyle);

CDNs not up to date

The docs mention 3.0 being available via the cdns, but those links just 404. The latest version on both cdns is v 2.0.0.

balanceText isn't called on resize for manually triggered elements

This might be by design, but calling $('.my-class').balanceText() doesn't attach resize handlers to the balanced element. This is unexpected behaviour for a polyfill, since alignment generally responds to resizing.

Not attaching a listener could be useful in some cases; for example, if hundreds of elements are dynamically added to the page, balanced, then replaced with other elements. This is an edge-case, and can be handled with a skipResize flag: $el.balanceText(true).

Users can implement their own debounce function in the meantime, but it's not ideal. Happy to make a PR if this is something you're interested in!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.