Last active
August 29, 2015 14:24
-
-
Save charliepark/a124b768c4db4ff3404d to your computer and use it in GitHub Desktop.
This is one approach; another is here: https://gist.github.com/charliepark/80f4bea797d17adc44e0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var BalancedMeasures = { | |
minimumScreenSizeToRunOn: 992, | |
classNameToMeasure: "graf--pullquote", | |
breakCode: "<br class='bmjs'>", | |
charactersToTriggerOrphanScreen: /[,\.\?\!]/, | |
run: function(classToRunOn){ | |
if(this.onSmallerScreen()){return;} | |
var elements = this.getElementsToMeasure(classToRunOn); | |
Log.toConsole(elements.length); | |
for(var i = 0; i < elements.length; i++){ | |
arrayOfSubstrings = this.getArrayOfBalancedSubstrings(elements[i]); | |
Log.toConsole(arrayOfSubstrings); | |
arrayOfSubstrings = this.screenForOrphans(arrayOfSubstrings); | |
elements[i].innerHTML = arrayOfSubstrings.join(this.breakCode); | |
} | |
}, | |
// onSmallerScreen | |
// | |
// The goal of BalancedMeasures is to create a more square-ish text block for pullquotes. | |
// The CSS for tablets and phones already handles this well, so we only apply this library | |
// on larger (desktop) screens. | |
// | |
// returns a boolean | |
onSmallerScreen: function(){ | |
var body = document.getElementsByTagName("body")[0]; | |
var bodyWidth = parseFloat(window.getComputedStyle(body, null).getPropertyValue('width')); | |
return bodyWidth < this.minimumScreenSizeToRunOn; | |
}, | |
getElementsToMeasure: function(classToRunOn){ | |
if(typeof(classToRunOn) === 'undefined'){classToRunOn = this.classNameToMeasure} | |
return document.getElementsByClassName(classToRunOn); | |
}, | |
// getArrayOfBalancedSubstrings | |
// | |
// | |
// | |
// Note: this assumes that ">" and "<" in text is properly encoded (<, >) | |
// | |
// Example: | |
// | |
// | |
// returns an array of strings | |
getArrayOfBalancedSubstrings: function(element){ | |
var idealLength = this.getIdealCharactersPerLineCount(element); | |
Log.toConsole("The idealLength is " + idealLength); | |
var string = element.innerHTML.split(this.breakCode).join(" ").replace(" "," "); | |
var isDomContent = false; | |
var counter = 0; // this only counts actual text (no DOM code) | |
var substringStart = 0; | |
var substringLength = 0; // this counts all characters, including DOM code | |
var substrings = []; // what we'll be adding to and then returning | |
for(var i = 0; i < string.length; i++){ | |
substringLength++; | |
// We DON'T want to factor DOM element data into our substring's length. | |
if(isDomContent && string[i] != ">"){continue;} | |
if(string[i] === "<"){isDomContent = true; continue;} | |
if(string[i] === ">"){isDomContent = false;continue;} | |
// At this point, we're only dealing with actual text from the element. | |
// Are we looking at the very last character in the whole string? If so, push this substring over to the array. | |
if(i == string.length - 1){substrings.push( string.substr( substringStart, substringLength ).trim() );continue;} | |
counter++; | |
// We haven't yet hit our idealLength, so we can just move on to the next character. | |
if( counter < idealLength ){continue;} | |
// At this point, we're only dealing with text that's longer than our desired string length. | |
// Specifically, we only care about breaking at spaces. Otherwise, the function just moves along. | |
if(string[i] === " "){ | |
substrings.push( string.substr( substringStart, substringLength ).trim() ); | |
substringStart += substringLength; | |
substringLength = 0; | |
counter = 0; | |
} | |
} | |
return substrings; | |
}, | |
getIdealCharactersPerLineCount: function(element){ | |
var text = element.textContent; Log.toConsole("text: "+text);Log.toConsole("text.length: "+text.length); | |
var numberOfLines = Math.round(this.getNumberOfLinesInElement(element)); Log.toConsole("numberOfLines: "+numberOfLines); | |
return text.length / numberOfLines; | |
}, | |
getNumberOfLinesInElement: function(element){ | |
var height = element.offsetHeight; Log.toConsole("height: "+height); | |
height = height - parseFloat( window.getComputedStyle(element, null).getPropertyValue('padding-top') ); | |
height = height - parseFloat( window.getComputedStyle(element, null).getPropertyValue('padding-bottom') ); | |
Log.toConsole("height: "+height); | |
var lineHeight = this.getLineHeightOfElement(element); Log.toConsole("lineHeight: "+lineHeight); | |
return height / lineHeight; | |
}, | |
getLineHeightOfElement: function(element){ | |
var lineHeight = window.getComputedStyle(element, null).getPropertyValue('line-height'); | |
if(lineHeight === "normal"){ | |
lineHeight = ( 1.14 * parseFloat( window.getComputedStyle(element, null).getPropertyValue('font-size') ) ); | |
} | |
Log.toConsole("lineHeight: "+lineHeight); | |
return parseFloat(lineHeight); | |
}, | |
screenForOrphans: function(arrayOfSubstrings){ | |
for(var i = 0; i < arrayOfSubstrings.length - 1; i++){ | |
var lineAsArray = arrayOfSubstrings[i].split(" "); | |
var orphanIsPresent = this.orphanIsPresent(lineAsArray); | |
if(orphanIsPresent){ | |
lastWord = lineAsArray.pop(); | |
arrayOfSubstrings[i] = lineAsArray.join(" ").trim(); | |
arrayOfSubstrings[i+1] = lastWord+" "+arrayOfSubstrings[i+1]; | |
} | |
} | |
return arrayOfSubstrings; | |
}, | |
orphanIsPresent: function(lineAsArray){ | |
var lastCharacterOfSecondToLastWord = lineAsArray.slice(-2)[0].slice(-1); | |
return lastCharacterOfSecondToLastWord.match(this.charactersToTriggerOrphanScreen); | |
} | |
}; | |
Log = { | |
toConsole: function(string){ | |
// console.log(string); // uncomment to get sanity checks in the console; remove `Log.toConsole()`s before minifying! | |
} | |
}; | |
//// TODO | |
//// - run on every page load | |
//// - run on every resize |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment