Skip to content

Commit

Permalink
quick hack to move things around
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Rix committed Feb 28, 2012
1 parent c6a6687 commit 72a0400
Show file tree
Hide file tree
Showing 4 changed files with 324 additions and 2 deletions.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ <h1>
</h1>

<p>
A simple <a href="http://jqueryui.com">jQuery UI</a> widget to manage a list of items. It's fully unit tested too, you can <a href="tests.html">run the tests</a> if you like.
A simple <a href="http://jqueryui.com">jQuery UI</a> widget to manage a list of items. It's fully unit tested too, you can <a href="test/spec-runner.html">run the tests</a> if you like.
</p>

<h2>Example</h2>
Expand All @@ -38,7 +38,7 @@ <h2>Example</h2>
</div>
<pre id="debug_log">Loading...</pre>

<h2>You might also like...</h2>
<h2 style="clear:both;padding-top: 10px">You might also like...</h2>
<p>I've made a couple other form related jQuery UI widgets, <a href="http://rixth.github.com/customSelect/">jquery.customSelect</a> and <a href="http://rixth.github.com/customRadio/">jquery.customRadio</a>.</p>

<h2 style="clear:both;padding-top:10px;">Download</h2>
Expand Down
39 changes: 39 additions & 0 deletions src/bubbleBox.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.ui-bubblebox-list {
list-style: none;
padding: 0;
margin: 10px 0;
}

.ui-bubblebox-item {
border:1px solid #cdd5e6;
background:#eff2f7;
color:#6a6a6a;
border-radius: 3px;
-moz-border-radius: 3px;

padding: 5px 15px 5px 5px;
margin: 5px 0;

position: relative;
}

.ui-bubblebox-item span {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.ui-bubblebox-removeItem {
font-size:12px;
font-weight:bold;
cursor:pointer;
color:#abb8d4;

position: absolute;
right: 5px;
top: 5px;
}
.ui-bubblebox-removeItem:hover {
color: #bbb;
}
89 changes: 89 additions & 0 deletions src/jquery.bubbleBox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*! bubbleBox: a jQuery UI widget to manage a list of items
http://github.com/rixth/bubbleBox
*/

/*jshint browser: true, jquery: true, indent: 2, white: true, curly: true, forin: true, noarg: true, immed: true, newcap: true, noempty: true */
(function ($) {
$.widget("ui.bubbleBox", {
options: {
showRemoveButton: true,
list: null,
allowDupes: false,
seedData: [],
triggerKeyCodes: [
13, // enter
44, 188, // the two possibilities for comma
59, 186 // the two possibilities for semicolon
]
},
_create: function () {
var self = this;

self.input = self.element;

self.options.list || (self.options.list = '#' + self.input.attr('id') + '_list');
self.list = $(self.options.list).addClass('ui-bubblebox-list');

// Bind events
if (self.options.showRemoveButton) {
self.list.delegate('.ui-bubblebox-removeItem', 'click', function (event) {
self.removeItem($(this.parentNode));
});
}

self.element.bind('blur keydown', function (event) {
var newValue = self.input.val();

if (event.type === 'blur' || jQuery.inArray(event.which, self.options.triggerKeyCodes) !== -1) {
if (self.addItem(newValue, event)) {
self.input.val('');
event.preventDefault();
}
} else if (newValue === '' && event.type === 'keydown' && event.which === 8) {
self.removeItem(self.list.find('li:last-child'));
}
});

// Insert start data
$(self.options.seedData).each(function () {
self.addItem(this);
});
},
_createBubble: function (value) {
var removeButton = this.options.showRemoveButton ? '<div class="ui-bubblebox-removeItem">x</div>' : '';
return $('<li class="ui-bubblebox-item"><span>' + value + '</span>' + removeButton + '</li>');
},
val: function () {
var values = [];
this.list.children().each(function () {
values.push($(this).find('span').text());
});
return values;
},
removeItem: function (item, event) {
item.remove();
this._trigger('remove', event, { value: item.find('span').text(), node: item[0] });
},
addItem: function (value, event) {
var self = this,
bubble;

if (!self.options.allowDupes && jQuery.inArray(value, self.val()) !== -1) {
return false;
}

if (value !== '' && !value.match(/^\s+$/) && self._trigger('beforeAdd', event, { value: value }) !== false) {
bubble = self._createBubble(value);
self.list.append(bubble);
self._trigger('afterAdd', event, { value: value, node: bubble[0] });
return bubble;
} else {
return false;
}
},
_destroy: function () {
this.list.empty().removeClass('ui-bubblebox-list');
$.Widget.prototype.destroy.apply(this, arguments);
}
});
}(jQuery));
194 changes: 194 additions & 0 deletions test/bubbleBox.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*globals jasmine, describe, it, beforeEach, setFixtures, expect */

describe("bubblebox", function () {
function resetHtml() {
setFixtures('<ul id="bubbleBox_list"></ul><div id="bubbleBox"></div>');
}

var itemSelector = '.ui-bubblebox-item',
box, list;

beforeEach(function() {
resetHtml();
$('#bubbleBox').bubbleBox();
box = $('#bubbleBox');
list = $('#bubbleBox_list');
});

function addThreeItems() {
box.bubbleBox("addItem", "my value 1");
box.bubbleBox("addItem", "my value 2");
box.bubbleBox("addItem", "my value 3");
}

function numberOfItems() {
return $('#bubbleBox_list ' + itemSelector).length;
}

describe("adding items", function () {
var enterEvent = $.Event('keydown');
enterEvent.which = $.ui.keyCode.ENTER;

it("should do nothing when the input is empty", function () {
box.trigger(enterEvent);
expect(numberOfItems()).toEqual(0);
});
it("should add a new item when enter is pressed", function () {
box.val('my value');
box.trigger(enterEvent);
expect(numberOfItems()).toEqual(1);
});
it("should clear the input after an item is added", function () {
box.val('my value');
box.trigger(enterEvent);
expect(numberOfItems()).toEqual(1);
expect(box.val()).toEqual('');
});
it("should add a new item when comma is pressed", function () {
box.val('my value');
var commaEvent = $.Event('keydown');

commaEvent.which = $.ui.keyCode.COMMA;
box.trigger(commaEvent);
expect(numberOfItems()).toEqual(1);
});
it("should add a new item when semicolon is pressed", function () {
box.val('my value');
var semicolonEvent = $.Event('keydown');

semicolonEvent.which = 59;
box.trigger(semicolonEvent);
expect(numberOfItems()).toEqual(1);
});
it("should add a new item when input focus is lost", function () {
box.val('my value');
box.trigger($.Event('blur'));
expect($('#bubbleBox_list ' + itemSelector).length).toEqual(1);
});

describe("duplicate item handling", function () {
it("should not allow duplicates by default", function () {
addThreeItems();
expect(numberOfItems()).toEqual(3);
box.val('my value 1');
box.trigger(enterEvent);
expect(numberOfItems()).toEqual(3);
});
it("should allow duplicates when allowDupes is true", function () {
box.bubbleBox("option", "allowDupes", true);
addThreeItems();
expect(numberOfItems()).toEqual(3);
box.val('my value 1');
box.trigger(enterEvent);
expect(numberOfItems()).toEqual(4);
});
});

describe("seeding start data", function () {
it("should add items upon instantiation", function () {
resetHtml();
box.bubbleBox({
seedData: ['Trulia', 'Zillow']
});
expect(numberOfItems()).toEqual(2);
expect(box.bubbleBox("val").join(",")).toEqual("Trulia,Zillow");
});
});
});

describe("removing items", function () {
it("should remove items when the close button is clicked", function () {
addThreeItems();
expect(numberOfItems()).toEqual(3);
$('#bubbleBox_list>li>div').eq(0).click();
expect(numberOfItems()).toEqual(2);
});
it("should remove the last item when the delete key is pressed when the input is blank", function () {
var backspaceEvent = $.Event('keydown'),
box = $('#bubbleBox');
backspaceEvent.which = 8;

addThreeItems();
box.trigger(backspaceEvent);
expect(box.bubbleBox("val").join(',')).toEqual('my value 1,my value 2');
});
});

describe("events", function () {
describe("add events", function () {
var enterEvent = $.Event('keydown');
enterEvent.which = $.ui.keyCode.ENTER;

it("should trigger the beforeAdd event before a new item is added", function () {
box.val('my value');
var callback = jasmine.createSpy();

box.bind('bubbleboxbeforeadd', callback);
box.trigger(enterEvent);
expect(callback).toHaveBeenCalledWith(jasmine.any(Object), { value: 'my value' });
});
it("should not add an item if any of the beforeAdd handlers return false", function () {
box.val('my value');
var callback = jasmine.createSpy().andReturn(false);

box.bind('bubbleboxbeforeadd', callback);
box.trigger(enterEvent);

expect(callback).toHaveBeenCalledWith(jasmine.any(Object), { value: 'my value' });
expect(numberOfItems()).toEqual(0);
});
it("should trigger the afterAdd event after a new item is added", function () {
box.val('my value');
var callback = jasmine.createSpy();

box.bind('bubbleboxafteradd', callback);
box.trigger(enterEvent);

expect(callback).toHaveBeenCalledWith(jasmine.any(Object), { value: 'my value', node: jasmine.any(Object)});
expect(numberOfItems()).toEqual(1);
});
});

describe("remove events", function () {
it("should trigger the remove event when an event is removed via the delete key", function () {
var backspaceEvent = $.Event('keydown'),
callback = jasmine.createSpy();

backspaceEvent.which = 8;

box.bind('bubbleboxremove', callback);
addThreeItems();
box.trigger(backspaceEvent);
expect(numberOfItems()).toEqual(2);
expect(callback).toHaveBeenCalledWith(jasmine.any(Object), { value: 'my value 3', node: jasmine.any(Object)});
});
it("should trigger the remove event when an event is removed via the remove button", function () {
var callback = jasmine.createSpy();
box.bind('bubbleboxremove', callback);
addThreeItems();
$('#bubbleBox_list>li>div').eq(0).click();
expect(numberOfItems()).toEqual(2);
expect(callback).toHaveBeenCalledWith(jasmine.any(Object), { value: 'my value 1', node: jasmine.any(Object)});
});
});
});

describe("fetching the value", function () {
it("should return an array when the val() method is called", function () {
addThreeItems();
expect(box.bubbleBox("val").length).toEqual(3);
expect(box.bubbleBox("val")).toContain('my value 1');
expect(box.bubbleBox("val")).toContain('my value 2');
expect(box.bubbleBox("val")).toContain('my value 3');
});
});

describe("destroying", function () {
it("should empty the container upon destruction", function () {
addThreeItems();
expect(numberOfItems()).toEqual(3);
box.bubbleBox("destroy");
expect(numberOfItems()).toEqual(3);
});
});
});

0 comments on commit 72a0400

Please sign in to comment.