diff --git a/.gitignore b/.gitignore
index 29c0029..6e067fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,5 +14,6 @@ Thumbs.db
# NPM
/node_modules
yarn-error.log
+yarn.lock
!**/.gitkeep
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 20b0403..f6a03e0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Changes
+## unreleased
+
+ - FEATURE: Added truncate component. #32
+
## 1.4.1
- FEATURE: Added return of instance in startComponent. #30
diff --git a/scss/tools/_media.scss b/scss/tools/_media.scss
index 43d7d44..77c6c03 100644
--- a/scss/tools/_media.scss
+++ b/scss/tools/_media.scss
@@ -187,4 +187,3 @@ $media-breakpoints: $breakpoints !default;
}
}
}
-
diff --git a/src/components/truncate.js b/src/components/truncate.js
new file mode 100644
index 0000000..0106ff8
--- /dev/null
+++ b/src/components/truncate.js
@@ -0,0 +1,71 @@
+// Truncate text component module
+
+'use strict';
+
+var $ = require('jquery');
+var debounce = require('../services/debounce');
+
+module.exports = function Truncate() {
+ var truncate = {};
+
+ /**
+ * @example
+ *
+ * Lorem ipsum ...
+ *
+ *
+ * import truncate from 'massive-web/src/components/truncate';
+ * truncate.initialize($('#truncate'), {});
+ *
+ * @param {jQuery} $el
+ * @param {object} options
+ */
+ truncate.initialize = function initialize($el, options) {
+ truncate.$el = $el;
+
+ // Set default options if no custom options are defined
+ truncate.separator = options.separator || ' ...';
+ truncate.debounceDelay = options.debounceDelay || 250;
+
+ truncate.text = truncate.$el.text().trim();
+ truncate.$inner = $('').text(truncate.text).css('display', 'block');
+ truncate.$el.html(truncate.$inner).css('display', 'block');
+
+ truncate.calculateRegex();
+ truncate.calculateText();
+
+ $(window).on('resize', debounce(truncate.calculateText, truncate.debounceDelay));
+ };
+
+ /**
+ * Calculate regex based on the separator.
+ */
+ truncate.calculateRegex = function calculateRegex() {
+ var separatorRegex = truncate.separator.split('').map(c => '\\' + c).join('');
+ truncate.regex = new RegExp('\\W*\\s?(?:\\S*|\\S*' + separatorRegex + ')$');
+ };
+
+ /**
+ * Calculate output text based on the element's height.
+ */
+ truncate.calculateText = function calculateText() {
+ var height;
+
+ truncate.$inner.text(truncate.text);
+ height = truncate.$el.height();
+
+ while (truncate.$inner.outerHeight() > height) {
+ truncate.$inner.text(function(index, text) {
+ if (text === truncate.separator) {
+ return '';
+ }
+
+ return text.replace(truncate.regex, truncate.separator);
+ });
+ }
+ };
+
+ return {
+ initialize: truncate.initialize
+ };
+};
diff --git a/src/services/debounce.js b/src/services/debounce.js
new file mode 100644
index 0000000..9f7cb96
--- /dev/null
+++ b/src/services/debounce.js
@@ -0,0 +1,30 @@
+// Debounce function
+
+'use strict';
+
+/**
+ * Extracted from UnderscoreJS
+ *
+ * @ignore
+ */
+module.exports = function debounce(func, wait, immediate) {
+ var timeout;
+
+ return function() {
+ var context = this;
+ var args = arguments;
+
+ clearTimeout(timeout);
+ timeout = setTimeout(function() {
+ timeout = null;
+
+ if (!immediate) {
+ func.apply(context, args);
+ }
+ }, wait);
+
+ if (immediate && !timeout) {
+ func.apply(context, args);
+ }
+ };
+};