Skip to content

Commit

Permalink
Merge pull request twitter#1207 of git://github.com/twitter/typeahead.js
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomi Nokkala committed May 15, 2015
2 parents ccde793 + f269bf1 commit 4fb3ae4
Show file tree
Hide file tree
Showing 17 changed files with 183 additions and 60 deletions.
2 changes: 0 additions & 2 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ module.exports = function(grunt) {
bloodhound: {
src: '<%= tempDir %>/bloodhound.js',
objectToExport: 'Bloodhound',
amdModuleId: 'bloodhound',
deps: {
default: ['$'],
amd: ['jquery'],
Expand All @@ -145,7 +144,6 @@ module.exports = function(grunt) {
},
typeahead: {
src: '<%= tempDir %>/typeahead.jquery.js',
amdModuleId: 'typeahead.js',
deps: {
default: ['$'],
amd: ['jquery'],
Expand Down
21 changes: 12 additions & 9 deletions doc/bloodhound.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,9 @@ options you can configure.
the internal search index is insufficient or, if more configurability is
needed, a [remote options hash](#remote).

* `indexRemote` – Adds the data loaded from `remote` to the search index (where
`local` and `prefetch` are stored for retrieval). Defaults to `false`.

<!-- section links -->

[compare function]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Expand Down Expand Up @@ -252,15 +255,15 @@ When configuring `remote`, the following options are available.
* `url` – The URL remote data should be loaded from. **Required.**

* `prepare` – A function that provides a hook to allow you to prepare the
settings object passed to `transport` when a request is about to be made.
The function signature should be `prepare(query, settings)`, where `query` is
the query `#search` was called with and `settings` is the default settings
object created internally by the Bloodhound instance. The `prepare` function
should return a settings object. Defaults to the [identity function].
settings object passed to `transport` when a request is about to be made.
The function signature should be `prepare(query, settings)`, where `query` is
the query `#search` was called with and `settings` is the default settings
object created internally by the Bloodhound instance. The `prepare` function
should return a settings object. Defaults to the [identity function].

* `wildcard` – A convenience option for `prepare`. If set, `prepare` will be a
function that replaces the value of this option in `url` with the URI encoded
query.
function that replaces the value of this option in `url` with the URI encoded
query.

* `rateLimitBy` – The method used to rate-limit network requests. Can be either
`debounce` or `throttle`. Defaults to `debounce`.
Expand All @@ -269,8 +272,8 @@ When configuring `remote`, the following options are available.
`rateLimitBy`. Defaults to `300`.

* `transform` – A function with the signature `transform(response)` that allows
you to transform the remote response before the Bloodhound instance operates
on it. Defaults to the [identity function].
you to transform the remote response before the Bloodhound instance operates
on it. Defaults to the [identity function].

<!-- section links -->

Expand Down
17 changes: 10 additions & 7 deletions doc/jquery_typeahead.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,16 +212,19 @@ a typeahead.
occurred in.

* `typeahead:select` – Fired when a suggestion is selected. The event handler
will be invoked with 2 arguments: the jQuery event object and the suggestion
object that was selected.
will be invoked with 3 arguments: the jQuery event object, the suggestion
object that was selected, and the name of the dataset the suggestion belongs
to.

* `typeahead:autocomplete` – Fired when a autocompletion occurs. The
event handler will be invoked with 2 arguments: the jQuery event object and
the suggestion object that was used for autocompletion.
* `typeahead:autocomplete` – Fired when a autocompletion occurs. The event
handler will be invoked with 3 arguments: the jQuery event object, the
suggestion object that was used for autocompletion, and the name of the
dataset the suggestion belongs to.

* `typeahead:cursorchange` – Fired when the results container cursor moves. The
event handler will be invoked with 2 arguments: the jQuery event object and
the suggestion object that was moved to.
event handler will be invoked with 3 arguments: the jQuery event object, the
suggestion object that was moved to, and the name of the dataset the
suggestion belongs to.

* `typeahead:asyncrequest` – Fired when an async request for suggestions is
sent. The event handler will be invoked with 3 arguments: the jQuery event
Expand Down
9 changes: 8 additions & 1 deletion src/bloodhound/bloodhound.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var Bloodhound = (function() {
this.sorter = o.sorter;
this.identify = o.identify;
this.sufficient = o.sufficient;
this.indexRemote = o.indexRemote;

this.local = o.local;
this.remote = o.remote ? new Remote(o.remote) : null;
Expand Down Expand Up @@ -132,6 +133,9 @@ var Bloodhound = (function() {
search: function search(query, sync, async) {
var that = this, local;

sync = sync || _.noop;
async = async || _.noop;

local = this.sorter(this.index.search(query));

// return a copy to guarantee no changes within this scope
Expand Down Expand Up @@ -159,7 +163,10 @@ var Bloodhound = (function() {
}) && nonDuplicates.push(r);
});

async && async(nonDuplicates);
// #1148: Should Bloodhound index remote datums?
that.indexRemote && that.add(nonDuplicates);

async(nonDuplicates);
}
},

Expand Down
1 change: 1 addition & 0 deletions src/bloodhound/options_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var oParser = (function() {
datumTokenizer: null,
queryTokenizer: null,
sufficient: 5,
indexRemote: false,
sorter: null,
local: [],
prefetch: null,
Expand Down
1 change: 1 addition & 0 deletions src/bloodhound/remote.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var Remote = (function() {
this.url = o.url;
this.prepare = o.prepare;
this.transform = o.transform;
this.indexResponse = o.indexResponse;

this.transport = new Transport({
cache: o.cache,
Expand Down
16 changes: 9 additions & 7 deletions src/typeahead/dataset.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ var Dataset = (function() {
var keys, nameGenerator;

keys = {
dataset: 'tt-selectable-dataset',
val: 'tt-selectable-display',
obj: 'tt-selectable-object'
};
Expand Down Expand Up @@ -41,7 +42,7 @@ var Dataset = (function() {
www.mixin(this);

this.highlight = !!o.highlight;
this.name = o.name || nameGenerator();
this.name = _.toStr(o.name || nameGenerator());

this.limit = o.limit || 5;
this.displayFn = getDisplayFn(o.display || o.displayKey);
Expand Down Expand Up @@ -70,6 +71,7 @@ var Dataset = (function() {

if ($el.data(keys.obj)) {
return {
dataset: $el.data(keys.dataset) || '',
val: $el.data(keys.val) || '',
obj: $el.data(keys.obj) || null
};
Expand Down Expand Up @@ -108,7 +110,7 @@ var Dataset = (function() {
this._empty();
}

this.trigger('rendered', this.name, suggestions, false);
this.trigger('rendered', suggestions, false, this.name);
},

_append: function append(query, suggestions) {
Expand All @@ -129,7 +131,7 @@ var Dataset = (function() {
this._renderNotFound(query);
}

this.trigger('rendered', this.name, suggestions, true);
this.trigger('rendered', suggestions, true, this.name);
},

_renderSuggestions: function renderSuggestions(query, suggestions) {
Expand Down Expand Up @@ -189,6 +191,7 @@ var Dataset = (function() {
context = that._injectQuery(query, suggestion);

$el = $(that.templates.suggestion(context))
.data(keys.dataset, that.name)
.data(keys.obj, suggestion)
.data(keys.val, that.displayFn(suggestion))
.addClass(that.classes.suggestion + ' ' + that.classes.selectable);
Expand Down Expand Up @@ -242,7 +245,7 @@ var Dataset = (function() {
this.cancel = function cancel() {
canceled = true;
that.cancel = $.noop;
that.async && that.trigger('asyncCanceled', query);
that.async && that.trigger('asyncCanceled', query, that.name);
};

this.source(query, sync, async);
Expand All @@ -258,7 +261,7 @@ var Dataset = (function() {
that._overwrite(query, suggestions);

if (rendered < that.limit && that.async) {
that.trigger('asyncRequested', query);
that.trigger('asyncRequested', query, that.name);
}
}

Expand All @@ -269,10 +272,9 @@ var Dataset = (function() {
// do not render the suggestions as they've become outdated
if (!canceled && rendered < that.limit) {
that.cancel = $.noop;
rendered += suggestions.length;
that._append(query, suggestions.slice(0, that.limit - rendered));

that.async && that.trigger('asyncReceived', query);
that.async && that.trigger('asyncReceived', query, that.name);
}
}
},
Expand Down
7 changes: 2 additions & 5 deletions src/typeahead/event_bus.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@ var EventBus = (function() {
// ### private

_trigger: function(type, args) {
var $e;
var $e = $.Event(namespace + type);

$e = $.Event(namespace + type);
(args = args || []).unshift($e);

this.$el.trigger.apply(this.$el, args);
this.$el.trigger.call(this.$el, $e, args || []);

return $e;
},
Expand Down
1 change: 1 addition & 0 deletions src/typeahead/menu.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ var Menu = (function() {
},

open: function open() {
this.$node.scrollTop(0);
this.$node.addClass(this.classes.open);
},

Expand Down
2 changes: 1 addition & 1 deletion src/typeahead/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
}

else {
ttEach(this, function(t) { t.setVal(newVal); });
ttEach(this, function(t) { t.setVal(_.toStr(newVal)); });
return this;
}
},
Expand Down
20 changes: 11 additions & 9 deletions src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ var Typeahead = (function() {
this._updateHint();
},

_onDatasetRendered: function onDatasetRendered(type, dataset, suggestions, async) {
_onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) {
this._updateHint();
this.eventBus.trigger('render', suggestions, async, dataset);
},
Expand Down Expand Up @@ -347,10 +347,10 @@ var Typeahead = (function() {
select: function select($selectable) {
var data = this.menu.getSelectableData($selectable);

if (data && !this.eventBus.before('select', data.obj)) {
if (data && !this.eventBus.before('select', data.obj, data.dataset)) {
this.input.setQuery(data.val, true);

this.eventBus.trigger('select', data.obj);
this.eventBus.trigger('select', data.obj, data.dataset);
this.close();

// return true if selection succeeded
Expand All @@ -367,9 +367,9 @@ var Typeahead = (function() {
data = this.menu.getSelectableData($selectable);
isValid = data && query !== data.val;

if (isValid && !this.eventBus.before('autocomplete', data.obj)) {
if (isValid && !this.eventBus.before('autocomplete', data.obj, data.dataset)) {
this.input.setQuery(data.val);
this.eventBus.trigger('autocomplete', data.obj);
this.eventBus.trigger('autocomplete', data.obj, data.dataset);

// return true if autocompletion succeeded
return true;
Expand All @@ -379,18 +379,20 @@ var Typeahead = (function() {
},

moveCursor: function moveCursor(delta) {
var query, $candidate, data, payload, cancelMove;
var query, $candidate, data, suggestion, datasetName, cancelMove;

query = this.input.getQuery();

$candidate = this.menu.selectableRelativeToCursor(delta);
data = this.menu.getSelectableData($candidate);
payload = data ? data.obj : null;
suggestion = data ? data.obj : null;
datasetName = data ? data.dataset : null;

// update will return true when it's a new query and new suggestions
// need to be fetched – in this case we don't want to move the cursor
cancelMove = this._minLengthMet() && this.menu.update(query);

if (!cancelMove && !this.eventBus.before('cursorchange', payload)) {
if (!cancelMove && !this.eventBus.before('cursorchange', suggestion, datasetName)) {
this.menu.setCursor($candidate);

// cursor moved to different selectable
Expand All @@ -404,7 +406,7 @@ var Typeahead = (function() {
this._updateHint();
}

this.eventBus.trigger('cursorchange', payload);
this.eventBus.trigger('cursorchange', suggestion, datasetName);

// return true if move succeeded
return true;
Expand Down
51 changes: 51 additions & 0 deletions test/bloodhound/bloodhound_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,57 @@ describe('Bloodhound', function() {

function fakeGet(o, cb) { cb(fixtures.data.animals); }
});

it('should not add remote data to index if indexRemote is false', function() {
this.bloodhound = build({
identify: function(d) { return d.value; },
remote: '/remote'
});
this.bloodhound.remote.get.andCallFake(fakeGet);

spyOn(this.bloodhound, 'add');
this.bloodhound.search('dog');

expect(this.bloodhound.add).not.toHaveBeenCalled();

function fakeGet(o, cb) { cb(fixtures.data.animals); }
});

it('should add remote data to index if indexRemote is true', function() {
this.bloodhound = build({
identify: function(d) { return d.value; },
indexRemote: true,
remote: '/remote'
});
this.bloodhound.remote.get.andCallFake(fakeGet);

spyOn(this.bloodhound, 'add');
this.bloodhound.search('dog');

expect(this.bloodhound.add).toHaveBeenCalledWith(fixtures.data.animals);

function fakeGet(o, cb) { cb(fixtures.data.animals); }
});

it('should not add duplicates from remote to index', function() {
this.bloodhound = build({
identify: function(d) { return d.value; },
indexRemote: true,
local: fixtures.data.animals,
remote: '/remote'
});
this.bloodhound.remote.get.andCallFake(fakeGet);

spyOn(this.bloodhound, 'add');
this.bloodhound.search('dog');

expect(this.bloodhound.add).toHaveBeenCalledWith([
{ value: 'cat' },
{ value: 'moose' }
]);

function fakeGet(o, cb) { cb(fixtures.data.animals); }
});
});

// helper functions
Expand Down
Loading

0 comments on commit 4fb3ae4

Please sign in to comment.