You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
6.8 KiB
266 lines
6.8 KiB
/*!
|
|
* jQuery.ellipsis
|
|
* http://github.com/jjenzz/jquery.ellipsis
|
|
* --------------------------------------------------------------------------
|
|
* Copyright (c) 2013 J. Smith (@jjenzz)
|
|
* Dual licensed under the MIT and GPL licenses:
|
|
* http://www.opensource.org/licenses/mit-license.php
|
|
* http://www.gnu.org/licenses/gpl.html
|
|
*
|
|
* adds a class to the last 'allowed' line of text so you can apply
|
|
* text-overflow: ellipsis;
|
|
*/
|
|
(function(factory) {
|
|
'use strict';
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
// AMD. register as an anonymous module
|
|
define(['jquery'], factory);
|
|
} else {
|
|
// browser globals
|
|
factory(jQuery);
|
|
}
|
|
}(function($) {
|
|
'use strict';
|
|
|
|
var namespace = 'ellipsis',
|
|
span = '<span style="white-space: nowrap;">',
|
|
defaults = {
|
|
lines: 'auto',
|
|
ellipClass: 'ellip',
|
|
responsive: false
|
|
};
|
|
|
|
/**
|
|
* Ellipsis()
|
|
* --------------------------------------------------------------------------
|
|
* @param {Node} el
|
|
* @param {Object} opts
|
|
*/
|
|
function Ellipsis(el, opts) {
|
|
var base = this,
|
|
currLine = 0,
|
|
lines = [],
|
|
setStartEllipAt,
|
|
startEllipAt,
|
|
resizeTimer,
|
|
currOffset,
|
|
lineHeight,
|
|
contHeight,
|
|
words,
|
|
htmlEntities;
|
|
|
|
// List of HTML entities for escaping.
|
|
htmlEntities = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
'`': '`'
|
|
};
|
|
|
|
base.$cont = $(el);
|
|
base.opts = $.extend({}, defaults, opts);
|
|
|
|
/**
|
|
* create() happens once when
|
|
* instance is created
|
|
*/
|
|
function create() {
|
|
base.text = base.$cont.text();
|
|
base.opts.ellipLineClass = base.opts.ellipClass + '-line';
|
|
|
|
base.$el = $('<span class="' + base.opts.ellipClass + '" />');
|
|
base.$el.text(base.text);
|
|
|
|
base.$cont.empty().append(base.$el);
|
|
|
|
init();
|
|
}
|
|
|
|
/**
|
|
* init()
|
|
*/
|
|
function init() {
|
|
|
|
// if they only want one line just add
|
|
// the class and do nothing else
|
|
if (typeof base.opts.lines === 'number' && base.opts.lines < 2) {
|
|
base.$el.addClass(base.opts.ellipLineClass);
|
|
return;
|
|
}
|
|
|
|
contHeight = base.$cont.height();
|
|
|
|
// if they only want to ellipsis the overflow
|
|
// then do nothing if there is no overflow
|
|
if (base.opts.lines === 'auto' && base.$el.prop('scrollHeight') <= contHeight) {
|
|
return;
|
|
}
|
|
|
|
if (!setStartEllipAt) {
|
|
return;
|
|
}
|
|
|
|
// create an array of words from our string
|
|
words = $.trim(escapeText(base.text)).split(/\s+/);
|
|
|
|
// wrap each word in a span and temporarily append to the DOM
|
|
base.$el.html(span + words.join('</span> ' + span) + '</span>');
|
|
|
|
// loop through words to determine which word the
|
|
// ellipsis container should start from (need to
|
|
// re-query spans from DOM so we can get their offset)
|
|
base.$el.find('span').each(setStartEllipAt);
|
|
|
|
// startEllipAt could be 0 so make sure we're
|
|
// checking undefined instead of falsey
|
|
if (startEllipAt != null) {
|
|
updateText(startEllipAt);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* updateText() updates the text in the DOM
|
|
* with a span around the line that needs
|
|
* to be truncated
|
|
*
|
|
* @param {Number} i
|
|
*/
|
|
function updateText(nth) {
|
|
// add a span that wraps from nth
|
|
// word to the end of the string
|
|
words[nth] = '<span class="' + base.opts.ellipLineClass + '">' + words[nth];
|
|
words.push('</span>');
|
|
|
|
// update the DOM with
|
|
// our new string/markup
|
|
base.$el.html(words.join(' '));
|
|
}
|
|
|
|
function escapeText(text){
|
|
return String(text).replace(/[&<>"'\/]/g, function (s) {
|
|
return htmlEntities[s];
|
|
});
|
|
}
|
|
|
|
// only define the method if it's required
|
|
if (base.opts.lines === 'auto') {
|
|
|
|
/**
|
|
* setStartEllipByHeight() sets the start
|
|
* position to the first word in the last
|
|
* line of the element that doesn't overflow
|
|
*
|
|
* @param {Number} i
|
|
* @param {Node} word
|
|
*/
|
|
var setStartEllipByHeight = function(i, word) {
|
|
var $word = $(word),
|
|
top = $word.position().top;
|
|
|
|
lineHeight = lineHeight || $word.height();
|
|
|
|
if (top === currOffset) {
|
|
// if it's top matches currOffset
|
|
// then it's on the same line
|
|
// as the previous word
|
|
lines[currLine].push($word);
|
|
} else {
|
|
// otherwise we're
|
|
// on a new line
|
|
currOffset = top;
|
|
currLine += 1;
|
|
lines[currLine] = [$word];
|
|
}
|
|
|
|
// if the bottom of the word is outside
|
|
// the element (overflowing) then
|
|
// stop looping and set startEllipAt to
|
|
// the first word in the previous line
|
|
if (top + lineHeight > contHeight) {
|
|
startEllipAt = i - lines[currLine - 1].length;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
setStartEllipAt = setStartEllipByHeight;
|
|
}
|
|
|
|
// only define the method if it's required
|
|
if (typeof base.opts.lines === 'number' && base.opts.lines > 1) {
|
|
|
|
/**
|
|
* setStartEllipByLine() sets the start
|
|
* position to the first word in the line
|
|
* that was passed to opts. This forces
|
|
* the ellipsis on a specific line
|
|
* regardless of overflow
|
|
*
|
|
* @param {Number} i
|
|
* @param {Node} word
|
|
*/
|
|
var setStartEllipByLine = function(i, word) {
|
|
var $word = $(word),
|
|
top = $word.position().top;
|
|
|
|
// if top isn't currOfset
|
|
// then we're on a new line
|
|
if (top !== currOffset) {
|
|
currOffset = top;
|
|
currLine += 1;
|
|
}
|
|
|
|
// if the word's currLine is equal
|
|
// to the line limit passed via options
|
|
// then start ellip from this
|
|
// word and stop looping
|
|
if (currLine === base.opts.lines) {
|
|
startEllipAt = i;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
setStartEllipAt = setStartEllipByLine;
|
|
}
|
|
|
|
// only bind to window resize if required
|
|
if (base.opts.responsive) {
|
|
|
|
/**
|
|
* resize() resets necessary vars
|
|
* and content and then re-initialises
|
|
* the Ellipsis script
|
|
*/
|
|
var resize = function() {
|
|
lines = [];
|
|
currLine = 0;
|
|
currOffset = null;
|
|
startEllipAt = null;
|
|
base.$el.html(escapeText(base.text));
|
|
|
|
clearTimeout(resizeTimer);
|
|
resizeTimer = setTimeout(init, 100);
|
|
};
|
|
|
|
$(window).on('resize.' + namespace, resize);
|
|
}
|
|
|
|
// start 'er up
|
|
create();
|
|
}
|
|
|
|
$.fn[namespace] = function(opts) {
|
|
return this.each(function() {
|
|
try {
|
|
$(this).data(namespace, (new Ellipsis(this, opts)));
|
|
} catch (err) {
|
|
if (window.console) {
|
|
console.error(namespace + ': ' + err);
|
|
}
|
|
}
|
|
});
|
|
};
|
|
|
|
}));
|
|
|