;(function(window, $) { var counter = 0, $headCache = $('head'), oldBigText = window.BigText, oldjQueryMethod = $.fn.bigtext, BigText = { DEFAULT_MIN_FONT_SIZE_PX: null, DEFAULT_MAX_FONT_SIZE_PX: 528, GLOBAL_STYLE_ID: 'bigtext-style', STYLE_ID: 'bigtext-id', LINE_CLASS_PREFIX: 'bigtext-line', EXEMPT_CLASS: 'bigtext-exempt', DEFAULT_CHILD_SELECTOR: '> div', childSelectors: { div: '> div', ol: '> li', ul: '> li' }, noConflict: function(restore) { if(restore) { $.fn.bigtext = oldjQueryMethod; window.BigText = oldBigText; } return BigText; }, init: function() { if(!$('#'+BigText.GLOBAL_STYLE_ID).length) { $headCache.append(BigText.generateStyleTag(BigText.GLOBAL_STYLE_ID, ['.bigtext * { white-space: nowrap; }', '.bigtext .' + BigText.EXEMPT_CLASS + ', .bigtext .' + BigText.EXEMPT_CLASS + ' * { white-space: normal; }'])); } }, bindResize: function(eventName, resizeFunction) { if($.throttle) { // https://github.com/cowboy/jquery-throttle-debounce $(window).unbind(eventName).bind(eventName, $.throttle(100, resizeFunction)); } else { if($.fn.smartresize) { // https://github.com/lrbabe/jquery-smartresize/ eventName = 'smartresize.' + eventName; } $(window).unbind(eventName).bind(eventName, resizeFunction); } }, getStyleId: function(id) { return BigText.STYLE_ID + '-' + id; }, generateStyleTag: function(id, css) { return $('').attr('id', id); }, clearCss: function(id) { var styleId = BigText.getStyleId(id); $('#' + styleId).remove(); }, generateCss: function(id, linesFontSizes, lineWordSpacings, minFontSizes) { var css = []; BigText.clearCss(id); for(var j=0, k=linesFontSizes.length; j= maxWidth) { $line.css(property, ''); if(width == maxWidth) { return { match: 'exact', size: parseFloat((parseFloat(size) - .1).toFixed(3)) }; } return { match: 'estimate', size: parseFloat((parseFloat(size) - interval).toFixed(3)) }; } return false; } function calculateSizes($t, childSelector, maxWidth, maxFontSize, minFontSize) { var $c = $t.clone(true) .addClass('bigtext-cloned') .css({ 'min-width': parseInt(maxWidth, 10), width: 'auto', position: 'absolute', left: -9999, top: -9999 }).appendTo(document.body); // font-size isn't the only thing we can modify, we can also mess with: // word-spacing and letter-spacing. // Note: webkit does not respect subpixel letter-spacing or word-spacing, // nor does it respect hundredths of a font-size em. var fontSizes = [], wordSpacings = [], minFontSizes = [], ratios = []; $c.find(childSelector).css({ 'float': 'left', 'clear': 'left' }).each(function(lineNumber) { var $line = $(this), intervals = [4,1,.4,.1], lineMax; if($line.hasClass(BigText.EXEMPT_CLASS)) { fontSizes.push(null); ratios.push(null); minFontSizes.push(false); return; } // TODO we can cache this ratio? var autoGuessSubtraction = 20, // px currentFontSize = parseFloat($line.css('font-size')), lineWidth = $line.width(), ratio = (lineWidth / currentFontSize).toFixed(6), newFontSize = parseFloat(((maxWidth - autoGuessSubtraction) / ratio).toFixed(3)); outer: for(var m=0, n=intervals.length; m maxFontSize) { newFontSize = maxFontSize; break outer; } lineMax = testLineDimensions($line, maxWidth, 'font-size', newFontSize + j*intervals[m], intervals[m], 'px'); if(lineMax !== false) { newFontSize = lineMax.size; if(lineMax.match == 'exact') { break outer; } break inner; } } } ratios.push(maxWidth / newFontSize); if(newFontSize > maxFontSize) { fontSizes.push(maxFontSize); minFontSizes.push(false); } else if(!!minFontSize && newFontSize < minFontSize) { fontSizes.push(minFontSize); minFontSizes.push(true); } else { fontSizes.push(newFontSize); minFontSizes.push(false); } }).each(function(lineNumber) { var $line = $(this), wordSpacing = 0, interval = 1, maxWordSpacing; if($line.hasClass(BigText.EXEMPT_CLASS)) { wordSpacings.push(null); return; } // must re-use font-size, even though it was removed above. $line.css('font-size', fontSizes[lineNumber] + 'px'); for(var m=1, n=5; m