Skip to content

Commit

Permalink
[#2801] Add a related-item module
Browse files Browse the repository at this point in the history
This handles toggling between truncated description text and the
full text. Updated the CSS and added some unit tests.
  • Loading branch information
aron committed Aug 9, 2012
1 parent baca89a commit e83df46
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 1 deletion.
8 changes: 8 additions & 0 deletions ckan/public/base/css/main.css
Expand Up @@ -4799,6 +4799,14 @@ ol.media-grid:after {
.media-item .media-content {
min-height: 63px;
}
.related-item.expanded {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
background-color: #ffffff;
background-color: rgba(255, 255, 255, 0.9);
z-index: 2;
}
.media-wide {
padding: 0;
}
Expand Down
74 changes: 74 additions & 0 deletions ckan/public/base/javascript/modules/related-item.js
@@ -0,0 +1,74 @@
/* Module that handles related item elements, at the moment this consists of
* truncating the descriptions and allowing them to be toggled.
*
* truncate - The max number of characters in the description element.
* truncateMore - A locale string for the "more" text.
* truncateLess - A locale string for the "less" text.
* truncatePrefix - A prefix for the more/less strings.
* truncateSuffix - A suffix for the more/less strings.
* truncateSelector - A selector for the element to truncate.
* expandedClass - A class to apply to the element when expanded.
*/
this.ckan.module('related-item', function (jQuery, _) {
return {
/* options object can be extended using data-module-* attributes */
options: {
truncate: 55,
truncateMore: null,
truncateLess: null,
truncatePrefix: ' (',
truncateSuffix: ')',
truncateSelector: '.prose',
expandedClass: 'expanded',
i18n: {
more: _('show more'),
less: _('show less')
}
},

/* Initialises the module setting up elements and event listeners.
*
* Returns nothing.
*/
initialize: function () {
jQuery.proxyAll(this, /_on/);

var options = this.options;
this.description = this.$(options.truncateSelector);
this.truncated = this.description.truncate({
max_length: options.truncate,
more: options.truncateMore || this.i18n('more'),
less: options.truncateLess || this.i18n('less'),
link_prefix: options.truncatePrefix,
link_suffix: options.truncateSuffix
});

this.collapsedHeight = this.el.height();
this.truncated.on('expand.truncate', this._onExpand);
this.truncated.on('collapse.truncate', this._onCollapse);
},

/* Event handler called when the truncated text expands.
*
* event - An event object.
*
* Returns nothing.
*/
_onExpand: function () {
var diff = this.el.height() - this.collapsedHeight;
this.el.addClass(this.options.expandedClass);
this.el.css('margin-bottom', diff * -1);
},

/* Event handler called when the truncated text is collapsed.
*
* event - An event object.
*
* Returns nothing.
*/
_onCollapse: function () {
this.el.removeClass(this.options.expandedClass);
this.el.css('margin-bottom', '');
}
};
});
11 changes: 11 additions & 0 deletions ckan/public/base/less/media.less
Expand Up @@ -83,6 +83,17 @@ ol.media-grid {
min-height: 63px;
}

// This allows the truncated text on an item to expand over the element
// below it by applying a negative margin in JavaScript.
.related-item.expanded {
.border-radius(4px);
background-color: @moduleBackgroundColor;
background-color: @moduleExpandedBackgroundColor;
z-index: 2;
}

// Wide media elements

.media-wide {
padding: 0;
}
Expand Down
1 change: 1 addition & 0 deletions ckan/public/base/less/variables.less
Expand Up @@ -18,6 +18,7 @@
@moduleHeadingBackgroundColorStart: #f5f5f5;
@moduleHeadingBackgroundColorEnd: #f0f0f0;
@moduleHeadingActionTextColor: #8c8c8c;
@moduleExpandedBackgroundColor: rgba(255, 255, 255, 0.9);

@gutterX: 25px;
@gutterY: 20px;
Expand Down
2 changes: 2 additions & 0 deletions ckan/public/base/test/index.html
Expand Up @@ -48,6 +48,7 @@
<script src="../javascript/modules/resource-upload-field.js"></script>
<script src="../javascript/modules/confirm-delete.js"></script>
<script src="../javascript/modules/custom-fields.js"></script>
<script src="../javascript/modules/related-item.js"></script>

<!-- Suite -->
<script src="./spec/ckan.spec.js"></script>
Expand All @@ -61,6 +62,7 @@
<script src="./spec/modules/basic-form.spec.js"></script>
<script src="./spec/modules/autocomplete.spec.js"></script>
<script src="./spec/modules/custom-fields.spec.js"></script>
<script src="./spec/modules/related-item.spec.js"></script>
<script src="./spec/plugins/jquery.inherit.spec.js"></script>
<script src="./spec/plugins/jquery.proxy-all.spec.js"></script>
<script src="./spec/plugins/jquery.url-helpers.spec.js"></script>
Expand Down
87 changes: 87 additions & 0 deletions ckan/public/base/test/spec/modules/related-item.spec.js
@@ -0,0 +1,87 @@
/*globals describe before beforeEach afterEach it assert sinon ckan jQuery */
describe('ckan.module.RelatedItemModule()', function () {
var RelatedItemModule = ckan.module.registry['related-item'];

before(function (done) {
// Load our fixture into the this.fixture element.
this.loadFixture('related-item.html', function (html) {
this.template = html;
done();
});
});

beforeEach(function () {
this.truncated = jQuery('<div/>');
jQuery.fn.truncate = sinon.stub().returns(this.truncated);

// Grab the loaded fixture.
this.el = this.fixture.html(this.template).children();
this.sandbox = ckan.sandbox();
this.sandbox.body = this.fixture;
this.module = new RelatedItemModule(this.el, {}, this.sandbox);
});

afterEach(function () {
this.module.teardown();
delete jQuery.fn.truncate;
});

describe('.initialize()', function () {
it('should truncate the .prose element', function () {
this.module.initialize();
assert.called(jQuery.fn.truncate);
});

it('should pass the various options into the truncate plugin');

it('should cache the collapsed height of the plugin', function () {
this.module.initialize();
assert.ok(this.module.collapsedHeight);
});

it('should listen for the "truncate" events', function () {
var target = sinon.stub(this.truncated, 'on');
this.module.initialize();

assert.called(target);
assert.calledWith(target, 'expand.truncate', this.module._onExpand);
assert.calledWith(target, 'collapse.truncate', this.module._onCollapse);
});
});

describe('._onExpand(event)', function () {
it('should add the "expanded" class to the element', function () {
this.module._onExpand(jQuery.Event());
assert.isTrue(this.el.hasClass(this.module.options.expandedClass));
});

it('should add a bottom margin to the element', function () {
this.module._onExpand(jQuery.Event());
assert.ok(this.el.css('margin-bottom'));
});

it('should calcualte the difference between the current and cached height', function () {
var target = sinon.stub(this.el, 'css');
sinon.stub(this.el, 'height').returns(30);
this.module.collapsedHeight = 10;
this.module._onExpand(jQuery.Event());

assert.called(target);
assert.calledWith(target, 'margin-bottom', -20);
});
});

describe('._onCollapse(event)', function () {
it('should remove the "expanded" class from the element', function () {
this.el.addClass(this.module.options.expandedClass);
this.module._onCollapse(jQuery.Event());
assert.isFalse(this.el.hasClass(this.module.options.expandedClass));
});

it('should remove the bottom margin from the element', function () {
this.el.css('margin-bottom', -90);
this.module._onCollapse(jQuery.Event());
assert.equal(this.el.css('margin-bottom'), '0px');
});
});
});
3 changes: 2 additions & 1 deletion ckan/templates/snippets/scripts.html
Expand Up @@ -12,7 +12,7 @@
<script src="{% url_for_static "/base/javascript/plugins/jquery.date-helpers.js" %}"></script>
<script src="{% url_for_static "/base/javascript/plugins/jquery.slug.js" %}"></script>
<script src="{% url_for_static "/base/javascript/plugins/jquery.slug-preview.js" %}"></script>
<script src="{% url_for_static "/base/javascript/plugins/jquery.form-warning.js" %}"></script>
<script src="{% url_for_static "/base/javascript/plugins/jquery.truncator.js" %}"></script>
<script src="{% url_for_static '/base/javascript/sandbox.js' %}"></script>
<script src="{% url_for_static '/base/javascript/module.js' %}"></script>
<script src="{% url_for_static '/base/javascript/pubsub.js' %}"></script>
Expand All @@ -27,3 +27,4 @@
<script src="{% url_for_static '/base/javascript/modules/api-info.js' %}"></script>
<script src="{% url_for_static '/base/javascript/modules/autocomplete.js' %}"></script>
<script src="{% url_for_static '/base/javascript/modules/custom-fields.js' %}"></script>
<script src="{% url_for_static '/base/javascript/modules/related-item.js' %}"></script>

0 comments on commit e83df46

Please sign in to comment.